blend.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:53k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * blend.c: alpha blend 2 pictures together
  3.  *****************************************************************************
  4.  * Copyright (C) 2003-2008 the VideoLAN team
  5.  * $Id: 08fe36f55bb99f5890e2e2d2a9497f8d7d1f9223 $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *          Antoine Cellerier <dionoea @t videolan dot org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <assert.h>
  31. #include <vlc_common.h>
  32. #include <vlc_plugin.h>
  33. #include <vlc_vout.h>
  34. #include "vlc_filter.h"
  35. /*****************************************************************************
  36.  * Module descriptor
  37.  *****************************************************************************/
  38. static int  OpenFilter ( vlc_object_t * );
  39. static void CloseFilter( vlc_object_t * );
  40. vlc_module_begin ()
  41.     set_description( N_("Video pictures blending") )
  42.     set_capability( "video blending", 100 )
  43.     set_callbacks( OpenFilter, CloseFilter )
  44. vlc_module_end ()
  45. /*****************************************************************************
  46.  * filter_sys_t : filter descriptor
  47.  *****************************************************************************/
  48. struct filter_sys_t
  49. {
  50.     int i_dummy;
  51. };
  52. #define FCC_YUVA VLC_FOURCC('Y','U','V','A')
  53. #define FCC_YUVP VLC_FOURCC('Y','U','V','P')
  54. #define FCC_RGBA VLC_FOURCC('R','G','B','A')
  55. #define FCC_I420 VLC_FOURCC('I','4','2','0')
  56. #define FCC_YV12 VLC_FOURCC('Y','V','1','2')
  57. #define FCC_YUY2 VLC_FOURCC('Y','U','Y','2')
  58. #define FCC_UYVY VLC_FOURCC('U','Y','V','Y')
  59. #define FCC_YVYU VLC_FOURCC('Y','V','Y','U')
  60. #define FCC_RV15 VLC_FOURCC('R','V','1','5')
  61. #define FCC_RV16 VLC_FOURCC('R','V','1','6')
  62. #define FCC_RV24 VLC_FOURCC('R','V','2','4')
  63. #define FCC_RV32 VLC_FOURCC('R','V','3','2')
  64. /****************************************************************************
  65.  * Local prototypes
  66.  ****************************************************************************/
  67. static void Blend( filter_t *, picture_t *, picture_t *,
  68.                    int, int, int );
  69. /* YUVA */
  70. static void BlendYUVAI420( filter_t *, picture_t *, picture_t *,
  71.                            int, int, int, int, int );
  72. static void BlendYUVARV16( filter_t *, picture_t *, picture_t *,
  73.                            int, int, int, int, int );
  74. static void BlendYUVARV24( filter_t *, picture_t *, picture_t *,
  75.                            int, int, int, int, int );
  76. static void BlendYUVAYUVPacked( filter_t *, picture_t *, picture_t *,
  77.                                 int, int, int, int, int );
  78. /* I420, YV12 */
  79. static void BlendI420I420( filter_t *, picture_t *, picture_t *,
  80.                            int, int, int, int, int );
  81. static void BlendI420I420_no_alpha(
  82.                            filter_t *, picture_t *, picture_t *,
  83.                            int, int, int, int );
  84. static void BlendI420R16( filter_t *, picture_t *, picture_t *,
  85.                            int, int, int, int, int );
  86. static void BlendI420R24( filter_t *, picture_t *, picture_t *,
  87.                           int, int, int, int, int );
  88. static void BlendI420YUVPacked( filter_t *, picture_t *,
  89.                                 picture_t *, int, int, int, int, int );
  90. /* YUVP */
  91. static void BlendPalI420( filter_t *, picture_t *, picture_t *,
  92.                           int, int, int, int, int );
  93. static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *,
  94.                                int, int, int, int, int );
  95. static void BlendPalRV( filter_t *, picture_t *, picture_t *,
  96.                         int, int, int, int, int );
  97. /* RGBA */
  98. static void BlendRGBAI420( filter_t *, picture_t *, picture_t *,
  99.                            int, int, int, int, int );
  100. static void BlendRGBAYUVPacked( filter_t *, picture_t *,
  101.                                 picture_t *, int, int, int, int, int );
  102. static void BlendRGBAR16( filter_t *, picture_t *, picture_t *,
  103.                           int, int, int, int, int );
  104. static void BlendRGBAR24( filter_t *, picture_t *, picture_t *,
  105.                           int, int, int, int, int );
  106. /*****************************************************************************
  107.  * OpenFilter: probe the filter and return score
  108.  *****************************************************************************/
  109. static int OpenFilter( vlc_object_t *p_this )
  110. {
  111.     filter_t *p_filter = (filter_t*)p_this;
  112.     filter_sys_t *p_sys;
  113.     /* Check if we can handle that format.
  114.      * We could try to use a chroma filter if we can't. */
  115.     int in_chroma = p_filter->fmt_in.video.i_chroma;
  116.     int out_chroma = p_filter->fmt_out.video.i_chroma;
  117.     if( ( in_chroma  != FCC_YUVA && in_chroma  != FCC_I420 &&
  118.           in_chroma  != FCC_YV12 && in_chroma  != FCC_YUVP &&
  119.           in_chroma  != FCC_RGBA ) ||
  120.         ( out_chroma != FCC_I420 && out_chroma != FCC_YUY2 &&
  121.           out_chroma != FCC_YV12 && out_chroma != FCC_UYVY &&
  122.           out_chroma != FCC_YVYU && out_chroma != FCC_RV15 &&
  123.           out_chroma != FCC_YVYU && out_chroma != FCC_RV16 &&
  124.           out_chroma != FCC_RV24 && out_chroma != FCC_RV32 ) )
  125.     {
  126.         return VLC_EGENERIC;
  127.     }
  128.     /* Allocate the memory needed to store the decoder's structure */
  129.     p_filter->p_sys = p_sys = malloc(sizeof(filter_sys_t));
  130.     if( !p_sys )
  131.         return VLC_ENOMEM;
  132.     /* Misc init */
  133.     p_filter->pf_video_blend = Blend;
  134.     msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
  135.              (char *)&p_filter->fmt_in.video.i_chroma,
  136.              (char *)&p_filter->fmt_out.video.i_chroma );
  137.     return VLC_SUCCESS;
  138. }
  139. /*****************************************************************************
  140.  * CloseFilter: clean up the filter
  141.  *****************************************************************************/
  142. static void CloseFilter( vlc_object_t *p_this )
  143. {
  144.     filter_t *p_filter = (filter_t*)p_this;
  145.     filter_sys_t *p_sys = p_filter->p_sys;
  146.     free( p_sys );
  147. }
  148. /****************************************************************************
  149.  * Blend: the whole thing
  150.  ****************************************************************************
  151.  * This function is called just after the thread is launched.
  152.  ****************************************************************************/
  153. typedef void (*BlendFunction)( filter_t *,
  154.                        picture_t *, picture_t *,
  155.                        int , int , int , int , int );
  156. #define FCC_PLANAR_420 { FCC_I420, FCC_YV12, 0 }
  157. #define FCC_PACKED_422 { FCC_YUY2, FCC_UYVY, FCC_YVYU, 0 }
  158. #define FCC_RGB_16 { FCC_RV15, FCC_RV16, 0 }
  159. #define FCC_RGB_24 { FCC_RV24, FCC_RV32, 0 }
  160. #define BLEND_CFG( fccSrc, fctPlanar, fctPacked, fctRgb16, fctRgb24  ) 
  161.     { .src = fccSrc, .p_dst = FCC_PLANAR_420, .pf_blend = fctPlanar }, 
  162.     { .src = fccSrc, .p_dst = FCC_PACKED_422, .pf_blend = fctPacked }, 
  163.     { .src = fccSrc, .p_dst = FCC_RGB_16,     .pf_blend = fctRgb16  }, 
  164.     { .src = fccSrc, .p_dst = FCC_RGB_24,     .pf_blend = fctRgb24  }
  165. static const struct
  166. {
  167.     vlc_fourcc_t src;
  168.     vlc_fourcc_t p_dst[16];
  169.     BlendFunction pf_blend;
  170. } p_blend_cfg[] = {
  171.     BLEND_CFG( FCC_YUVA, BlendYUVAI420, BlendYUVAYUVPacked, BlendYUVARV16, BlendYUVARV24 ),
  172.     BLEND_CFG( FCC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ),
  173.     BLEND_CFG( FCC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ),
  174.     BLEND_CFG( FCC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
  175.     BLEND_CFG( FCC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
  176.     { 0, {0,}, NULL }
  177. };
  178. static void Blend( filter_t *p_filter,
  179.                    picture_t *p_dst, picture_t *p_src,
  180.                    int i_x_offset, int i_y_offset, int i_alpha )
  181. {
  182.     int i_width, i_height;
  183.     if( i_alpha == 0 )
  184.         return;
  185.     i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
  186.                     (int)p_filter->fmt_in.video.i_visible_width);
  187.     i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
  188.                      (int)p_filter->fmt_in.video.i_visible_height);
  189.     if( i_width <= 0 || i_height <= 0 )
  190.         return;
  191.     video_format_FixRgb( &p_filter->fmt_out.video );
  192.     video_format_FixRgb( &p_filter->fmt_in.video );
  193. #if 0
  194.     msg_Dbg( p_filter, "chroma: %4.4s -> %4.4sn",
  195.              (char *)&p_filter->fmt_in.video.i_chroma,
  196.              (char *)&p_filter->fmt_out.video.i_chroma );
  197. #endif
  198.     for( int i = 0; p_blend_cfg[i].src != 0; i++ )
  199.     {
  200.         if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma )
  201.             continue;
  202.         for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ )
  203.         {
  204.             if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma )
  205.                 continue;
  206.             p_blend_cfg[i].pf_blend( p_filter, p_dst, p_src,
  207.                                      i_x_offset, i_y_offset,
  208.                                      i_width, i_height, i_alpha );
  209.             return;
  210.         }
  211.     }
  212.     msg_Dbg( p_filter, "no matching alpha blending routine "
  213.              "(chroma: %4.4s -> %4.4s)",
  214.              (char *)&p_filter->fmt_in.video.i_chroma,
  215.              (char *)&p_filter->fmt_out.video.i_chroma );
  216. }
  217. /***********************************************************************
  218.  * Utils
  219.  ***********************************************************************/
  220. static inline uint8_t vlc_uint8( int v )
  221. {
  222.     if( v > 255 )
  223.         return 255;
  224.     else if( v < 0 )
  225.         return 0;
  226.     return v;
  227. }
  228. #define MAX_TRANS 255
  229. #define TRANS_BITS  8
  230. static inline int vlc_blend( int v1, int v2, int a )
  231. {
  232.     /* TODO bench if the tests really increase speed */
  233.     if( a == 0 )
  234.         return v2;
  235.     else if( a == MAX_TRANS )
  236.         return v1;
  237.     return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
  238. }
  239. static inline int vlc_alpha( int t, int a )
  240. {
  241.     if( a == 255 )
  242.         return t;
  243.     return (t * a) / 255;
  244. }
  245. static inline void yuv_to_rgb( int *r, int *g, int *b,
  246.                                uint8_t y1, uint8_t u1, uint8_t v1 )
  247. {
  248.     /* macros used for YUV pixel conversions */
  249. #   define SCALEBITS 10
  250. #   define ONE_HALF  (1 << (SCALEBITS - 1))
  251. #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
  252.     int y, cb, cr, r_add, g_add, b_add;
  253.     cb = u1 - 128;
  254.     cr = v1 - 128;
  255.     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
  256.     g_add = - FIX(0.34414*255.0/224.0) * cb
  257.             - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
  258.     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
  259.     y = (y1 - 16) * FIX(255.0/219.0);
  260.     *r = vlc_uint8( (y + r_add) >> SCALEBITS );
  261.     *g = vlc_uint8( (y + g_add) >> SCALEBITS );
  262.     *b = vlc_uint8( (y + b_add) >> SCALEBITS );
  263. #undef FIX
  264. #undef ONE_HALF
  265. #undef SCALEBITS
  266. }
  267. static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
  268.                                int r, int g, int b )
  269. {
  270.     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
  271.     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
  272.     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
  273. }
  274. static uint8_t *vlc_plane_start( int *pi_pitch,
  275.                                  picture_t *p_picture,
  276.                                  int i_plane,
  277.                                  int i_x_offset, int i_y_offset,
  278.                                  const video_format_t *p_fmt,
  279.                                  int r )
  280. {
  281.     const int i_pitch = p_picture->p[i_plane].i_pitch;
  282.     uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
  283.     const int i_dx = ( i_x_offset + p_fmt->i_x_offset ) / r;
  284.     const int i_dy = ( i_y_offset + p_fmt->i_y_offset ) / r;
  285.     if( pi_pitch )
  286.         *pi_pitch = i_pitch;
  287.     return &p_pixels[ i_dy * i_pitch + i_dx ];
  288. }
  289. static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma )
  290. {
  291.     static const struct {
  292.         vlc_fourcc_t chroma;
  293.         int y, u ,v;
  294.     } p_index[] = {
  295.         { FCC_YUY2, 0, 1, 3 },
  296.         { FCC_UYVY, 1, 0, 2 },
  297.         { FCC_YVYU, 0, 3, 1 },
  298.         { 0, 0, 0, 0 }
  299.     };
  300.     int i;
  301.     for( i = 0; p_index[i].chroma != 0; i++ )
  302.     {
  303.         if( p_index[i].chroma == i_chroma )
  304.             break;
  305.     }
  306.     *pi_y = p_index[i].y;
  307.     *pi_u = p_index[i].u;
  308.     *pi_v = p_index[i].v;
  309. }
  310. static void vlc_blend_packed( uint8_t *p_dst,
  311.                               int i_offset0, int i_offset1, int i_offset2,
  312.                               int c0, int c1, int c2, int i_alpha,
  313.                               bool b_do12 )
  314. {
  315.     p_dst[i_offset0] = vlc_blend( c0, p_dst[i_offset0], i_alpha );
  316.     if( b_do12 )
  317.     {
  318.         p_dst[i_offset1] = vlc_blend( c1, p_dst[i_offset1], i_alpha );
  319.         p_dst[i_offset2] = vlc_blend( c2, p_dst[i_offset2], i_alpha );
  320.     }
  321. }
  322. static void vlc_blend_rgb16( uint16_t *p_dst,
  323.                              int R, int G, int B, int i_alpha,
  324.                              const video_format_t *p_fmt )
  325. {
  326.     const int i_pix = *p_dst;
  327.     const int r = ( i_pix & p_fmt->i_rmask ) >> p_fmt->i_lrshift;
  328.     const int g = ( i_pix & p_fmt->i_gmask ) >> p_fmt->i_lgshift;
  329.     const int b = ( i_pix & p_fmt->i_bmask ) >> p_fmt->i_lbshift;
  330.     *p_dst = ( vlc_blend( R >> p_fmt->i_rrshift, r, i_alpha ) << p_fmt->i_lrshift ) |
  331.              ( vlc_blend( G >> p_fmt->i_rgshift, g, i_alpha ) << p_fmt->i_lgshift ) |
  332.              ( vlc_blend( B >> p_fmt->i_rbshift, b, i_alpha ) << p_fmt->i_lbshift );
  333. }
  334. static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex,
  335.                            const video_format_t *p_fmt )
  336. {
  337.     if( p_fmt->i_chroma != FCC_RV24 && p_fmt->i_chroma != FCC_RV32 )
  338.         return;
  339.     /* XXX it will works only if mask are 8 bits aligned */
  340. #ifdef WORDS_BIGENDIAN
  341.     const int i_mask_bits = p_fmt->i_chroma == FCC_RV24 ? 24 : 32;
  342.     *pi_rindex = ( i_mask_bits - p_fmt->i_lrshift ) / 8;
  343.     *pi_gindex = ( i_mask_bits - p_fmt->i_lgshift ) / 8;
  344.     *pi_bindex = ( i_mask_bits - p_fmt->i_lbshift ) / 8;
  345. #else
  346.     *pi_rindex = p_fmt->i_lrshift / 8;
  347.     *pi_gindex = p_fmt->i_lgshift / 8;
  348.     *pi_bindex = p_fmt->i_lbshift / 8;
  349. #endif
  350. }
  351. /***********************************************************************
  352.  * YUVA
  353.  ***********************************************************************/
  354. static void BlendYUVAI420( filter_t *p_filter,
  355.                            picture_t *p_dst, picture_t *p_src,
  356.                            int i_x_offset, int i_y_offset,
  357.                            int i_width, int i_height, int i_alpha )
  358. {
  359.     int i_src_pitch, i_dst_pitch;
  360.     uint8_t *p_src_y, *p_dst_y;
  361.     uint8_t *p_src_u, *p_dst_u;
  362.     uint8_t *p_src_v, *p_dst_v;
  363.     uint8_t *p_trans;
  364.     int i_x, i_y, i_trans = 0;
  365.     bool b_even_scanline = i_y_offset % 2;
  366.     p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
  367.                                i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
  368.     p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
  369.                                i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
  370.     p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
  371.                                i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
  372.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  373.                                0, 0, &p_filter->fmt_in.video, 1 );
  374.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  375.                                0, 0, &p_filter->fmt_in.video, 2 );
  376.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  377.                                0, 0, &p_filter->fmt_in.video, 2 );
  378.     p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
  379.                                0, 0, &p_filter->fmt_in.video, 1 );
  380.     /* Draw until we reach the bottom of the subtitle */
  381.     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
  382.          p_dst_y += i_dst_pitch, p_src_y += i_src_pitch,
  383.          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
  384.          p_src_u += i_src_pitch,
  385.          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
  386.          p_src_v += i_src_pitch )
  387.     {
  388.         b_even_scanline = !b_even_scanline;
  389.         /* Draw until we reach the end of the line */
  390.         for( i_x = 0; i_x < i_width; i_x++ )
  391.         {
  392.             if( p_trans )
  393.                 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
  394.             if( !i_trans )
  395.                 continue;
  396.             /* Blending */
  397.             p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_trans );
  398.             if( b_even_scanline && i_x % 2 == 0 )
  399.             {
  400.                 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x], p_dst_u[i_x/2], i_trans );
  401.                 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x], p_dst_v[i_x/2], i_trans );
  402.             }
  403.         }
  404.     }
  405. }
  406. static void BlendYUVARV16( filter_t *p_filter,
  407.                            picture_t *p_dst_pic, picture_t *p_src,
  408.                            int i_x_offset, int i_y_offset,
  409.                            int i_width, int i_height, int i_alpha )
  410. {
  411.     int i_src_pitch, i_dst_pitch;
  412.     uint8_t *p_dst, *p_src_y;
  413.     uint8_t *p_src_u, *p_src_v;
  414.     uint8_t *p_trans;
  415.     int i_x, i_y, i_pix_pitch, i_trans = 0;
  416.     int r, g, b;
  417.     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
  418.     i_dst_pitch = p_dst_pic->p->i_pitch;
  419.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  420.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  421.             p_dst_pic->p->i_pitch *
  422.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  423.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  424.                                0, 0, &p_filter->fmt_in.video, 1 );
  425.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  426.                                0, 0, &p_filter->fmt_in.video, 2 );
  427.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  428.                                0, 0, &p_filter->fmt_in.video, 2 );
  429.     p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
  430.                                0, 0, &p_filter->fmt_in.video, 1 );
  431.     /* Draw until we reach the bottom of the subtitle */
  432.     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
  433.          p_dst += i_dst_pitch,
  434.          p_src_y += i_src_pitch, p_src_u += i_src_pitch,
  435.          p_src_v += i_src_pitch )
  436.     {
  437.         /* Draw until we reach the end of the line */
  438.         for( i_x = 0; i_x < i_width; i_x++ )
  439.         {
  440.             if( p_trans )
  441.                 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
  442.             if( !i_trans )
  443.                 continue;
  444.             /* Blending */
  445.             yuv_to_rgb( &r, &g, &b,
  446.                         p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
  447.             vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
  448.                              r, g, b, i_trans, &p_filter->fmt_out.video );
  449.         }
  450.     }
  451. }
  452. static void BlendYUVARV24( filter_t *p_filter,
  453.                            picture_t *p_dst_pic, picture_t *p_src,
  454.                            int i_x_offset, int i_y_offset,
  455.                            int i_width, int i_height, int i_alpha )
  456. {
  457.     int i_src_pitch, i_dst_pitch;
  458.     uint8_t *p_dst, *p_src_y;
  459.     uint8_t *p_src_u, *p_src_v;
  460.     uint8_t *p_trans;
  461.     int i_x, i_y, i_pix_pitch, i_trans = 0;
  462.     int r, g, b;
  463.     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
  464.     i_dst_pitch = p_dst_pic->p->i_pitch;
  465.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  466.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  467.             p_dst_pic->p->i_pitch *
  468.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  469.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  470.                                0, 0, &p_filter->fmt_in.video, 1 );
  471.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  472.                                0, 0, &p_filter->fmt_in.video, 2 );
  473.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  474.                                0, 0, &p_filter->fmt_in.video, 2 );
  475.     p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
  476.                                0, 0, &p_filter->fmt_in.video, 1 );
  477.     if( (i_pix_pitch == 4)
  478.      && (((((intptr_t)p_dst)|i_dst_pitch) /* FIXME? */
  479.           & 3) == 0) )
  480.     {
  481.         /*
  482.         ** if picture pixels are 32 bits long and lines addresses are 32 bit
  483.         ** aligned, optimize rendering
  484.         */
  485.         uint32_t *p32_dst = (uint32_t *)p_dst;
  486.         uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
  487.         int i_rshift, i_gshift, i_bshift;
  488.         uint32_t i_rmask, i_gmask, i_bmask;
  489.         i_rmask = p_filter->fmt_out.video.i_rmask;
  490.         i_gmask = p_filter->fmt_out.video.i_gmask;
  491.         i_bmask = p_filter->fmt_out.video.i_bmask;
  492.         i_rshift = p_filter->fmt_out.video.i_lrshift;
  493.         i_gshift = p_filter->fmt_out.video.i_lgshift;
  494.         i_bshift = p_filter->fmt_out.video.i_lbshift;
  495.         /* Draw until we reach the bottom of the subtitle */
  496.         for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
  497.              p32_dst += i32_dst_pitch,
  498.              p_src_y += i_src_pitch, p_src_u += i_src_pitch,
  499.              p_src_v += i_src_pitch )
  500.         {
  501.             /* Draw until we reach the end of the line */
  502.             for( i_x = 0; i_x < i_width; i_x++ )
  503.             {
  504.                 if( p_trans )
  505.                     i_trans = vlc_alpha( p_trans[i_x], i_alpha );
  506.                 if( !i_trans )
  507.                     continue;
  508.                 if( i_trans == MAX_TRANS )
  509.                 {
  510.                     /* Completely opaque. Completely overwrite underlying pixel */
  511.                     yuv_to_rgb( &r, &g, &b,
  512.                                 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
  513.                     p32_dst[i_x] = (r<<i_rshift) |
  514.                                    (g<<i_gshift) |
  515.                                    (b<<i_bshift);
  516.                 }
  517.                 else
  518.                 {
  519.                     /* Blending */
  520.                     uint32_t i_pix_dst = p32_dst[i_x];
  521.                     yuv_to_rgb( &r, &g, &b,
  522.                                 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
  523.                     p32_dst[i_x] = ( vlc_blend( r, (i_pix_dst & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
  524.                                    ( vlc_blend( g, (i_pix_dst & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
  525.                                    ( vlc_blend( b, (i_pix_dst & i_bmask)>>i_bshift, i_trans ) << i_bshift );
  526.                 }
  527.             }
  528.         }
  529.     }
  530.     else
  531.     {
  532.         int i_rindex, i_gindex, i_bindex;
  533.         uint32_t i_rmask, i_gmask, i_bmask;
  534.         i_rmask = p_filter->fmt_out.video.i_rmask;
  535.         i_gmask = p_filter->fmt_out.video.i_gmask;
  536.         i_bmask = p_filter->fmt_out.video.i_bmask;
  537.         vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
  538.         /* Draw until we reach the bottom of the subtitle */
  539.         for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
  540.              p_dst += i_dst_pitch,
  541.              p_src_y += i_src_pitch, p_src_u += i_src_pitch,
  542.              p_src_v += i_src_pitch )
  543.         {
  544.             /* Draw until we reach the end of the line */
  545.             for( i_x = 0; i_x < i_width; i_x++ )
  546.             {
  547.                 if( p_trans )
  548.                     i_trans = vlc_alpha( p_trans[i_x], i_alpha );
  549.                 if( !i_trans )
  550.                     continue;
  551.                 /* Blending */
  552.                 yuv_to_rgb( &r, &g, &b,
  553.                             p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
  554.                 vlc_blend_packed( &p_dst[ i_x * i_pix_pitch],
  555.                                   i_rindex, i_gindex, i_bindex,
  556.                                   r, g, b, i_alpha, true );
  557.             }
  558.         }
  559.     }
  560. }
  561. static void BlendYUVAYUVPacked( filter_t *p_filter,
  562.                                 picture_t *p_dst_pic, picture_t *p_src,
  563.                                 int i_x_offset, int i_y_offset,
  564.                                 int i_width, int i_height, int i_alpha )
  565. {
  566.     int i_src_pitch, i_dst_pitch;
  567.     uint8_t *p_dst, *p_src_y;
  568.     uint8_t *p_src_u, *p_src_v;
  569.     uint8_t *p_trans;
  570.     int i_x, i_y, i_pix_pitch, i_trans = 0;
  571.     bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
  572.     int i_l_offset, i_u_offset, i_v_offset;
  573.     vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
  574.                           p_filter->fmt_out.video.i_chroma );
  575.     i_pix_pitch = 2;
  576.     i_dst_pitch = p_dst_pic->p->i_pitch;
  577.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  578.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  579.             p_dst_pic->p->i_pitch *
  580.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  581.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  582.                                0, 0, &p_filter->fmt_in.video, 1 );
  583.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  584.                                0, 0, &p_filter->fmt_in.video, 2 );
  585.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  586.                                0, 0, &p_filter->fmt_in.video, 2 );
  587.     p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
  588.                                0, 0, &p_filter->fmt_in.video, 1 );
  589.     i_width &= ~1; /* Needs to be a multiple of 2 */
  590.     /* Draw until we reach the bottom of the subtitle */
  591.     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
  592.          p_dst += i_dst_pitch,
  593.          p_src_y += i_src_pitch, p_src_u += i_src_pitch,
  594.          p_src_v += i_src_pitch )
  595.     {
  596.         /* Draw until we reach the end of the line */
  597.         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
  598.         {
  599.             i_trans = vlc_alpha( p_trans[i_x], i_alpha );
  600.             if( !i_trans )
  601.                 continue;
  602.             /* Blending */
  603.             if( b_even )
  604.             {
  605.                 int i_u;
  606.                 int i_v;
  607.                 /* FIXME what's with 0xaa ? */
  608.                 if( p_trans[i_x+1] > 0xaa )
  609.                 {
  610.                     i_u = (p_src_u[i_x]+p_src_u[i_x+1])>>1;
  611.                     i_v = (p_src_v[i_x]+p_src_v[i_x+1])>>1;
  612.                 }
  613.                 else
  614.                 {
  615.                     i_u = p_src_u[i_x];
  616.                     i_v = p_src_v[i_x];
  617.                 }
  618.                 vlc_blend_packed( &p_dst[i_x * 2],
  619.                                   i_l_offset, i_u_offset, i_v_offset,
  620.                                   p_src_y[i_x], i_u, i_v, i_trans, true );
  621.             }
  622.             else
  623.             {
  624.                 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src_y[i_x], p_dst[i_x * 2 + i_l_offset], i_trans );
  625.             }
  626.         }
  627.     }
  628. }
  629. /***********************************************************************
  630.  * I420, YV12
  631.  ***********************************************************************/
  632. static void BlendI420I420( filter_t *p_filter,
  633.                            picture_t *p_dst, picture_t *p_src,
  634.                            int i_x_offset, int i_y_offset,
  635.                            int i_width, int i_height, int i_alpha )
  636. {
  637.     int i_src_pitch, i_dst_pitch;
  638.     uint8_t *p_src_y, *p_dst_y;
  639.     uint8_t *p_src_u, *p_dst_u;
  640.     uint8_t *p_src_v, *p_dst_v;
  641.     int i_x, i_y;
  642.     bool b_even_scanline = i_y_offset % 2;
  643.     if( i_alpha == 0xff )
  644.     {
  645.         BlendI420I420_no_alpha( p_filter, p_dst, p_src,
  646.                                 i_x_offset, i_y_offset, i_width, i_height );
  647.         return;
  648.     }
  649.     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
  650.     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
  651.               p_filter->fmt_out.video.i_x_offset +
  652.               p_dst->p[Y_PLANE].i_pitch *
  653.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  654.     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
  655.               p_filter->fmt_out.video.i_x_offset/2 +
  656.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
  657.               p_dst->p[U_PLANE].i_pitch;
  658.     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
  659.               p_filter->fmt_out.video.i_x_offset/2 +
  660.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
  661.               p_dst->p[V_PLANE].i_pitch;
  662.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  663.                                0, 0, &p_filter->fmt_in.video, 1 );
  664.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  665.                                0, 0, &p_filter->fmt_in.video, 2 );
  666.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  667.                                0, 0, &p_filter->fmt_in.video, 2 );
  668.     i_width &= ~1;
  669.     /* Draw until we reach the bottom of the subtitle */
  670.     for( i_y = 0; i_y < i_height; i_y++,
  671.          p_dst_y += i_dst_pitch,
  672.          p_src_y += i_src_pitch )
  673.     {
  674.         if( b_even_scanline )
  675.         {
  676.             p_dst_u  += i_dst_pitch/2;
  677.             p_dst_v  += i_dst_pitch/2;
  678.         }
  679.         b_even_scanline = !b_even_scanline;
  680.         /* Draw until we reach the end of the line */
  681.         for( i_x = 0; i_x < i_width; i_x++ )
  682.         {
  683.             if( !i_alpha )
  684.                 continue;
  685.             /* Blending */
  686.             p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_alpha );
  687.             if( b_even_scanline && i_x % 2 == 0 )
  688.             {
  689.                 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x/2], p_dst_u[i_x/2], i_alpha );
  690.                 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x/2], p_dst_v[i_x/2], i_alpha );
  691.             }
  692.         }
  693.         if( i_y%2 == 1 )
  694.         {
  695.             p_src_u += i_src_pitch/2;
  696.             p_src_v += i_src_pitch/2;
  697.         }
  698.     }
  699. }
  700. static void BlendI420I420_no_alpha( filter_t *p_filter,
  701.                                     picture_t *p_dst, picture_t *p_src,
  702.                                     int i_x_offset, int i_y_offset,
  703.                                     int i_width, int i_height )
  704. {
  705.     int i_src_pitch, i_dst_pitch;
  706.     uint8_t *p_src_y, *p_dst_y;
  707.     uint8_t *p_src_u, *p_dst_u;
  708.     uint8_t *p_src_v, *p_dst_v;
  709.     int i_y;
  710.     bool b_even_scanline = i_y_offset % 2;
  711.     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
  712.     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
  713.               p_filter->fmt_out.video.i_x_offset +
  714.               p_dst->p[Y_PLANE].i_pitch *
  715.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  716.     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
  717.               p_filter->fmt_out.video.i_x_offset/2 +
  718.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
  719.               p_dst->p[U_PLANE].i_pitch;
  720.     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
  721.               p_filter->fmt_out.video.i_x_offset/2 +
  722.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
  723.               p_dst->p[V_PLANE].i_pitch;
  724.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  725.                                0, 0, &p_filter->fmt_in.video, 1 );
  726.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  727.                                0, 0, &p_filter->fmt_in.video, 2 );
  728.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  729.                                0, 0, &p_filter->fmt_in.video, 2 );
  730.     i_width &= ~1;
  731.     /* Draw until we reach the bottom of the subtitle */
  732.     for( i_y = 0; i_y < i_height;
  733.             i_y++, p_dst_y += i_dst_pitch, p_src_y += i_src_pitch )
  734.     {
  735.         /* Completely opaque. Completely overwrite underlying pixel */
  736.         vlc_memcpy( p_dst_y, p_src_y, i_width );
  737.         if( b_even_scanline )
  738.         {
  739.             p_dst_u  += i_dst_pitch/2;
  740.             p_dst_v  += i_dst_pitch/2;
  741.         }
  742.         else
  743.         {
  744.             vlc_memcpy( p_dst_u, p_src_u, i_width/2 );
  745.             vlc_memcpy( p_dst_v, p_src_v, i_width/2 );
  746.         }
  747.         b_even_scanline = !b_even_scanline;
  748.         if( i_y%2 == 1 )
  749.         {
  750.             p_src_u += i_src_pitch/2;
  751.             p_src_v += i_src_pitch/2;
  752.         }
  753.     }
  754. }
  755. static void BlendI420R16( filter_t *p_filter,
  756.                           picture_t *p_dst_pic, picture_t *p_src,
  757.                           int i_x_offset, int i_y_offset,
  758.                           int i_width, int i_height, int i_alpha )
  759. {
  760.     int i_src_pitch, i_dst_pitch;
  761.     uint8_t *p_dst, *p_src_y;
  762.     uint8_t *p_src_u, *p_src_v;
  763.     int i_x, i_y, i_pix_pitch;
  764.     int r, g, b;
  765.     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
  766.     i_dst_pitch = p_dst_pic->p->i_pitch;
  767.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  768.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  769.             p_dst_pic->p->i_pitch *
  770.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  771.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  772.                                0, 0, &p_filter->fmt_in.video, 1 );
  773.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  774.                                0, 0, &p_filter->fmt_in.video, 2 );
  775.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  776.                                 0, 0, &p_filter->fmt_in.video, 2 );
  777.     /* Draw until we reach the bottom of the subtitle */
  778.     for( i_y = 0; i_y < i_height; i_y++,
  779.          p_dst += i_dst_pitch,
  780.          p_src_y += i_src_pitch )
  781.     {
  782.         /* Draw until we reach the end of the line */
  783.         for( i_x = 0; i_x < i_width; i_x++ )
  784.         {
  785.             /* Blending */
  786.             yuv_to_rgb( &r, &g, &b,
  787.                         p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
  788.             vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
  789.                              r, g, b, i_alpha, &p_filter->fmt_out.video );
  790.         }
  791.         if( i_y%2 == 1 )
  792.         {
  793.             p_src_u += i_src_pitch/2;
  794.             p_src_v += i_src_pitch/2;
  795.         }
  796.     }
  797. }
  798. static void BlendI420R24( filter_t *p_filter,
  799.                           picture_t *p_dst_pic, picture_t *p_src,
  800.                           int i_x_offset, int i_y_offset,
  801.                           int i_width, int i_height, int i_alpha )
  802. {
  803.     int i_src_pitch, i_dst_pitch;
  804.     uint8_t *p_dst, *p_src_y;
  805.     uint8_t *p_src_u, *p_src_v;
  806.     int i_x, i_y, i_pix_pitch;
  807.     int i_rindex, i_gindex, i_bindex;
  808.     int r, g, b;
  809.     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
  810.     i_dst_pitch = p_dst_pic->p->i_pitch;
  811.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  812.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  813.             p_dst_pic->p->i_pitch *
  814.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  815.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  816.                                0, 0, &p_filter->fmt_in.video, 1 );
  817.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  818.                                0, 0, &p_filter->fmt_in.video, 2 );
  819.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  820.                                0, 0, &p_filter->fmt_in.video, 2 );
  821.     vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
  822.     /* Draw until we reach the bottom of the subtitle */
  823.     for( i_y = 0; i_y < i_height; i_y++,
  824.          p_dst += i_dst_pitch,
  825.          p_src_y += i_src_pitch, p_src_u += i_src_pitch,
  826.          p_src_v += i_src_pitch )
  827.     {
  828.         /* Draw until we reach the end of the line */
  829.         for( i_x = 0; i_x < i_width; i_x++ )
  830.         {
  831.             if( !i_alpha )
  832.                 continue;
  833.             /* Blending */
  834.             yuv_to_rgb( &r, &g, &b,
  835.                         p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
  836.             vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
  837.                               i_rindex, i_gindex, i_bindex, r, g, b, i_alpha, true );
  838.         }
  839.         if( i_y%2 == 1 )
  840.         {
  841.             p_src_u += i_src_pitch/2;
  842.             p_src_v += i_src_pitch/2;
  843.         }
  844.     }
  845. }
  846. static void BlendI420YUVPacked( filter_t *p_filter,
  847.                                 picture_t *p_dst_pic, picture_t *p_src,
  848.                                 int i_x_offset, int i_y_offset,
  849.                                 int i_width, int i_height, int i_alpha )
  850. {
  851.     int i_src_pitch, i_dst_pitch;
  852.     uint8_t *p_dst, *p_src_y;
  853.     uint8_t *p_src_u, *p_src_v;
  854.     int i_x, i_y, i_pix_pitch;
  855.     bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
  856.     int i_l_offset, i_u_offset, i_v_offset;
  857.     vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
  858.                           p_filter->fmt_out.video.i_chroma );
  859.     i_pix_pitch = 2;
  860.     i_dst_pitch = p_dst_pic->p->i_pitch;
  861.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  862.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  863.             p_dst_pic->p->i_pitch *
  864.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  865.     p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
  866.                                0, 0, &p_filter->fmt_in.video, 1 );
  867.     p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
  868.                                0, 0, &p_filter->fmt_in.video, 2 );
  869.     p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
  870.                                0, 0, &p_filter->fmt_in.video, 2 );
  871.     i_width &= ~1; /* Needs to be a multiple of 2 */
  872.     /* Draw until we reach the bottom of the subtitle */
  873.     for( i_y = 0; i_y < i_height; i_y++,
  874.          p_dst += i_dst_pitch,
  875.          p_src_y += i_src_pitch, p_src_u += i_src_pitch,
  876.          p_src_v += i_src_pitch )
  877.     {
  878.         /* Draw until we reach the end of the line */
  879.         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
  880.         {
  881.             if( !i_alpha )
  882.                 continue;
  883.             /* Blending */
  884.             vlc_blend_packed( &p_dst[i_x * 2],
  885.                               i_l_offset, i_u_offset, i_v_offset,
  886.                               p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2], i_alpha, b_even );
  887.         }
  888.         if( i_y%2 == 1 )
  889.         {
  890.             p_src_u += i_src_pitch/2;
  891.             p_src_v += i_src_pitch/2;
  892.         }
  893.     }
  894. }
  895. /***********************************************************************
  896.  * YUVP
  897.  ***********************************************************************/
  898. static void BlendPalI420( filter_t *p_filter,
  899.                           picture_t *p_dst, picture_t *p_src_pic,
  900.                           int i_x_offset, int i_y_offset,
  901.                           int i_width, int i_height, int i_alpha )
  902. {
  903.     int i_src_pitch, i_dst_pitch;
  904.     uint8_t *p_src, *p_dst_y;
  905.     uint8_t *p_dst_u;
  906.     uint8_t *p_dst_v;
  907.     int i_x, i_y, i_trans;
  908.     bool b_even_scanline = i_y_offset % 2;
  909.     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
  910.     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
  911.               p_filter->fmt_out.video.i_x_offset +
  912.               p_dst->p[Y_PLANE].i_pitch *
  913.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  914.     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
  915.               p_filter->fmt_out.video.i_x_offset/2 +
  916.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
  917.               p_dst->p[U_PLANE].i_pitch;
  918.     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
  919.               p_filter->fmt_out.video.i_x_offset/2 +
  920.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
  921.               p_dst->p[V_PLANE].i_pitch;
  922.     i_src_pitch = p_src_pic->p->i_pitch;
  923.     p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
  924.             i_src_pitch * p_filter->fmt_in.video.i_y_offset;
  925. #define p_pal p_filter->fmt_in.video.p_palette->palette
  926.     /* Draw until we reach the bottom of the subtitle */
  927.     for( i_y = 0; i_y < i_height; i_y++,
  928.          p_dst_y += i_dst_pitch,
  929.          p_src += i_src_pitch,
  930.          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
  931.          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0 )
  932.     {
  933.         const uint8_t *p_trans = p_src;
  934.         b_even_scanline = !b_even_scanline;
  935.         /* Draw until we reach the end of the line */
  936.         for( i_x = 0; i_x < i_width; i_x++ )
  937.         {
  938.             i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
  939.             if( !i_trans )
  940.                 continue;
  941.             /* Blending */
  942.             p_dst_y[i_x] = vlc_blend( p_pal[p_src[i_x]][0], p_dst_y[i_x], i_trans );
  943.             if( b_even_scanline && ((i_x % 2) == 0) )
  944.             {
  945.                 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src[i_x]][1], p_dst_u[i_x/2], i_trans );
  946.                 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src[i_x]][2], p_dst_v[i_x/2], i_trans );
  947.             }
  948.         }
  949.     }
  950. #undef p_pal
  951. }
  952. static void BlendPalYUVPacked( filter_t *p_filter,
  953.                                picture_t *p_dst_pic, picture_t *p_src_pic,
  954.                                int i_x_offset, int i_y_offset,
  955.                                int i_width, int i_height, int i_alpha )
  956. {
  957.     int i_src_pitch, i_dst_pitch;
  958.     uint8_t *p_src, *p_dst;
  959.     int i_x, i_y, i_pix_pitch, i_trans;
  960.     bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
  961.     int i_l_offset, i_u_offset, i_v_offset;
  962.     vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
  963.                           p_filter->fmt_out.video.i_chroma );
  964.     i_pix_pitch = 2;
  965.     i_dst_pitch = p_dst_pic->p->i_pitch;
  966.     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
  967.             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
  968.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  969.     i_src_pitch = p_src_pic->p->i_pitch;
  970.     p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
  971.             i_src_pitch * p_filter->fmt_in.video.i_y_offset;
  972.     i_width &= ~1; /* Needs to be a multiple of 2 */
  973. #define p_pal p_filter->fmt_in.video.p_palette->palette
  974.     /* Draw until we reach the bottom of the subtitle */
  975.     for( i_y = 0; i_y < i_height; i_y++,
  976.          p_dst += i_dst_pitch, p_src += i_src_pitch )
  977.     {
  978.         const uint8_t *p_trans = p_src;
  979.         /* Draw until we reach the end of the line */
  980.         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
  981.         {
  982.             i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
  983.             if( !i_trans )
  984.                 continue;
  985.             /* Blending */
  986.             if( b_even )
  987.             {
  988.                 uint16_t i_u;
  989.                 uint16_t i_v;
  990.                 if( p_trans[i_x+1] > 0xaa )
  991.                 {
  992.                     i_u = (p_pal[p_src[i_x]][1] + p_pal[p_src[i_x+1]][1]) >> 1;
  993.                     i_v = (p_pal[p_src[i_x]][2] + p_pal[p_src[i_x+1]][2]) >> 1;
  994.                 }
  995.                 else
  996.                 {
  997.                     i_u = p_pal[p_src[i_x]][1];
  998.                     i_v = p_pal[p_src[i_x]][2];
  999.                 }
  1000.                 vlc_blend_packed( &p_dst[i_x * 2],
  1001.                                   i_l_offset, i_u_offset, i_v_offset,
  1002.                                   p_pal[p_src[i_x]][0], i_u, i_v, i_trans, true );
  1003.             }
  1004.             else
  1005.             {
  1006.                 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_pal[p_src[i_x]][0], p_dst[i_x * 2 + i_l_offset], i_trans );
  1007.             }
  1008.         }
  1009.     }
  1010. #undef p_pal
  1011. }
  1012. static void BlendPalRV( filter_t *p_filter,
  1013.                         picture_t *p_dst_pic, picture_t *p_src_pic,
  1014.                         int i_x_offset, int i_y_offset,
  1015.                         int i_width, int i_height, int i_alpha )
  1016. {
  1017.     int i_src_pitch, i_dst_pitch;
  1018.     uint8_t *p_src, *p_dst;
  1019.     int i_x, i_y, i_pix_pitch, i_trans;
  1020.     video_palette_t rgbpalette;
  1021.     int i_rindex, i_gindex, i_bindex;
  1022.     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
  1023.     i_dst_pitch = p_dst_pic->p->i_pitch;
  1024.     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
  1025.             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
  1026.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  1027.     i_src_pitch = p_src_pic->p->i_pitch;
  1028.     p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
  1029.             i_src_pitch * p_filter->fmt_in.video.i_y_offset;
  1030. #define p_pal p_filter->fmt_in.video.p_palette->palette
  1031. #define rgbpal rgbpalette.palette
  1032.     /* Convert palette first */
  1033.     for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && i_y < 256; i_y++ )
  1034.     {
  1035.         int r, g, b;
  1036.         yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
  1037.         rgbpal[i_y][0] = r;
  1038.         rgbpal[i_y][1] = g;
  1039.         rgbpal[i_y][2] = b;
  1040.     }
  1041.     /* */
  1042.     vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
  1043.     /* Draw until we reach the bottom of the subtitle */
  1044.     for( i_y = 0; i_y < i_height; i_y++,
  1045.          p_dst += i_dst_pitch, p_src += i_src_pitch )
  1046.     {
  1047.         const uint8_t *p_trans = p_src;
  1048.         /* Draw until we reach the end of the line */
  1049.         for( i_x = 0; i_x < i_width; i_x++ )
  1050.         {
  1051.             i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
  1052.             if( !i_trans )
  1053.                 continue;
  1054.             /* Blending */
  1055.             if( p_filter->fmt_out.video.i_chroma == FCC_RV15 || p_filter->fmt_out.video.i_chroma == FCC_RV16 )
  1056.                 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
  1057.                                   rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
  1058.                                   i_trans,
  1059.                                   &p_filter->fmt_out.video );
  1060.             else
  1061.                 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
  1062.                                   i_rindex, i_gindex, i_bindex,
  1063.                                   rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
  1064.                                   i_trans, true );
  1065.         }
  1066.     }
  1067. #undef p_pal
  1068. #undef rgbpal
  1069. }
  1070. /***********************************************************************
  1071.  * RGBA
  1072.  ***********************************************************************/
  1073. static void BlendRGBAI420( filter_t *p_filter,
  1074.                            picture_t *p_dst, picture_t *p_src_pic,
  1075.                            int i_x_offset, int i_y_offset,
  1076.                            int i_width, int i_height, int i_alpha )
  1077. {
  1078.     int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
  1079.     uint8_t *p_dst_y;
  1080.     uint8_t *p_dst_u;
  1081.     uint8_t *p_dst_v;
  1082.     uint8_t *p_src;
  1083.     int i_x, i_y, i_trans;
  1084.     uint8_t y, u, v;
  1085.     bool b_even_scanline = i_y_offset % 2;
  1086.     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
  1087.     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
  1088.               p_filter->fmt_out.video.i_x_offset +
  1089.               p_dst->p[Y_PLANE].i_pitch *
  1090.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  1091.     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
  1092.               p_filter->fmt_out.video.i_x_offset/2 +
  1093.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
  1094.               p_dst->p[U_PLANE].i_pitch;
  1095.     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
  1096.               p_filter->fmt_out.video.i_x_offset/2 +
  1097.               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
  1098.               p_dst->p[V_PLANE].i_pitch;
  1099.     i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
  1100.     i_src_pitch = p_src_pic->p->i_pitch;
  1101.     p_src = p_src_pic->p->p_pixels +
  1102.             p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
  1103.             p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
  1104.     /* Draw until we reach the bottom of the subtitle */
  1105.     for( i_y = 0; i_y < i_height; i_y++,
  1106.          p_dst_y += i_dst_pitch,
  1107.          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
  1108.          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
  1109.          p_src += i_src_pitch )
  1110.     {
  1111.         b_even_scanline = !b_even_scanline;
  1112.         /* Draw until we reach the end of the line */
  1113.         for( i_x = 0; i_x < i_width; i_x++ )
  1114.         {
  1115.             const int R = p_src[i_x * i_src_pix_pitch + 0];
  1116.             const int G = p_src[i_x * i_src_pix_pitch + 1];
  1117.             const int B = p_src[i_x * i_src_pix_pitch + 2];
  1118.             i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
  1119.             if( !i_trans )
  1120.                 continue;
  1121.             /* Blending */
  1122.             rgb_to_yuv( &y, &u, &v, R, G, B );
  1123.             p_dst_y[i_x] = vlc_blend( y, p_dst_y[i_x], i_trans );
  1124.             if( b_even_scanline && i_x % 2 == 0 )
  1125.             {
  1126.                 p_dst_u[i_x/2] = vlc_blend( u, p_dst_u[i_x/2], i_trans );
  1127.                 p_dst_v[i_x/2] = vlc_blend( v, p_dst_v[i_x/2], i_trans );
  1128.             }
  1129.         }
  1130.     }
  1131. }
  1132. static void BlendRGBAR24( filter_t *p_filter,
  1133.                           picture_t *p_dst_pic, picture_t *p_src_pic,
  1134.                           int i_x_offset, int i_y_offset,
  1135.                           int i_width, int i_height, int i_alpha )
  1136. {
  1137.     int i_src_pitch, i_dst_pitch;
  1138.     uint8_t *p_dst, *p_src;
  1139.     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
  1140.     int i_rindex, i_gindex, i_bindex;
  1141.     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
  1142.     i_dst_pitch = p_dst_pic->p->i_pitch;
  1143.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  1144.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  1145.             p_dst_pic->p->i_pitch *
  1146.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  1147.     i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
  1148.     i_src_pitch = p_src_pic->p->i_pitch;
  1149.     p_src = p_src_pic->p->p_pixels +
  1150.             p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
  1151.             p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
  1152.     vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
  1153.     /* Draw until we reach the bottom of the subtitle */
  1154.     for( i_y = 0; i_y < i_height; i_y++,
  1155.          p_dst += i_dst_pitch, p_src += i_src_pitch )
  1156.     {
  1157.         /* Draw until we reach the end of the line */
  1158.         for( i_x = 0; i_x < i_width; i_x++ )
  1159.         {
  1160.             const int R = p_src[i_x * i_src_pix_pitch + 0];
  1161.             const int G = p_src[i_x * i_src_pix_pitch + 1];
  1162.             const int B = p_src[i_x * i_src_pix_pitch + 2];
  1163.             i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
  1164.             if( !i_trans )
  1165.                 continue;
  1166.             /* Blending */
  1167.             vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
  1168.                               i_rindex, i_gindex, i_bindex,
  1169.                               R, G, B, i_trans, true );
  1170.         }
  1171.     }
  1172. }
  1173. static void BlendRGBAR16( filter_t *p_filter,
  1174.                           picture_t *p_dst_pic, picture_t *p_src_pic,
  1175.                           int i_x_offset, int i_y_offset,
  1176.                           int i_width, int i_height, int i_alpha )
  1177. {
  1178.     int i_src_pitch, i_dst_pitch;
  1179.     uint8_t *p_dst, *p_src;
  1180.     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
  1181.     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
  1182.     i_dst_pitch = p_dst_pic->p->i_pitch;
  1183.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  1184.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  1185.             p_dst_pic->p->i_pitch *
  1186.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  1187.     i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
  1188.     i_src_pitch = p_src_pic->p->i_pitch;
  1189.     p_src = p_src_pic->p->p_pixels +
  1190.             p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
  1191.             p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
  1192.     /* Draw until we reach the bottom of the subtitle */
  1193.     for( i_y = 0; i_y < i_height; i_y++,
  1194.          p_dst += i_dst_pitch, p_src += i_src_pitch )
  1195.     {
  1196.         /* Draw until we reach the end of the line */
  1197.         for( i_x = 0; i_x < i_width; i_x++ )
  1198.         {
  1199.             const int R = p_src[i_x * i_src_pix_pitch + 0];
  1200.             const int G = p_src[i_x * i_src_pix_pitch + 1];
  1201.             const int B = p_src[i_x * i_src_pix_pitch + 2];
  1202.             i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
  1203.             if( !i_trans )
  1204.                 continue;
  1205.             /* Blending */
  1206.             vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
  1207.                              R, G, B, i_trans, &p_filter->fmt_out.video );
  1208.         }
  1209.     }
  1210. }
  1211. static void BlendRGBAYUVPacked( filter_t *p_filter,
  1212.                                 picture_t *p_dst_pic, picture_t *p_src_pic,
  1213.                                 int i_x_offset, int i_y_offset,
  1214.                                 int i_width, int i_height, int i_alpha )
  1215. {
  1216.     int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
  1217.     uint8_t *p_dst, *p_src;
  1218.     int i_x, i_y, i_pix_pitch, i_trans;
  1219.     bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
  1220.     int i_l_offset, i_u_offset, i_v_offset;
  1221.     uint8_t y, u, v;
  1222.     vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
  1223.                           p_filter->fmt_out.video.i_chroma );
  1224.     i_pix_pitch = 2;
  1225.     i_dst_pitch = p_dst_pic->p->i_pitch;
  1226.     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
  1227.             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
  1228.             p_dst_pic->p->i_pitch *
  1229.             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
  1230.     i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
  1231.     i_src_pitch = p_src_pic->p->i_pitch;
  1232.     p_src = p_src_pic->p->p_pixels +
  1233.             p_filter->fmt_in.video.i_x_offset * i_src_pitch +
  1234.             p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
  1235.     i_width &= ~1; /* Needs to be a multiple of 2 */
  1236.     /* Draw until we reach the bottom of the subtitle */
  1237.     for( i_y = 0; i_y < i_height; i_y++,
  1238.          p_dst += i_dst_pitch,
  1239.          p_src += i_src_pitch )
  1240.     {
  1241.         /* Draw until we reach the end of the line */
  1242.         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
  1243.         {
  1244.             const int R = p_src[i_x * i_src_pix_pitch + 0];
  1245.             const int G = p_src[i_x * i_src_pix_pitch + 1];
  1246.             const int B = p_src[i_x * i_src_pix_pitch + 2];
  1247.             i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
  1248.             if( !i_trans )
  1249.                 continue;
  1250.             /* Blending */
  1251.             rgb_to_yuv( &y, &u, &v, R, G, B );
  1252.             vlc_blend_packed( &p_dst[i_x * 2],
  1253.                               i_l_offset, i_u_offset, i_v_offset,
  1254.                               y, u, v, i_trans, b_even );
  1255.         }
  1256.     }
  1257. }