+ int i_x, i_y, i_trans = 0;
+ bool b_even_scanline = i_y_offset % 2;
+
+ p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
+ i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
+ p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
+ i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
+ p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
+ i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
+
+ p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 1 );
+ p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 2 );
+ p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 2 );
+ p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 1 );
+
+ /* Draw until we reach the bottom of the subtitle */
+ for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
+ p_dst_y += i_dst_pitch, p_src_y += i_src_pitch,
+ p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
+ p_src_u += i_src_pitch,
+ p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
+ p_src_v += i_src_pitch )
+ {
+ b_even_scanline = !b_even_scanline;
+
+ /* Draw until we reach the end of the line */
+ for( i_x = 0; i_x < i_width; i_x++ )
+ {
+ if( p_trans )
+ i_trans = vlc_alpha( p_trans[i_x], i_alpha );
+
+ if( !i_trans )
+ continue;
+
+ /* Blending */
+ p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_trans );
+ if( b_even_scanline && i_x % 2 == 0 )
+ {
+ p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x], p_dst_u[i_x/2], i_trans );
+ p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x], p_dst_v[i_x/2], i_trans );
+ }
+ }
+ }
+}
+
+static void BlendYUVARV16( filter_t *p_filter,
+ picture_t *p_dst_pic, const picture_t *p_src,
+ int i_x_offset, int i_y_offset,
+ int i_width, int i_height, int i_alpha )
+{
+ int i_src_pitch, i_dst_pitch;
+ uint8_t *p_dst, *p_src_y;
+ uint8_t *p_src_u, *p_src_v;
+ uint8_t *p_trans;
+ int i_x, i_y, i_pix_pitch, i_trans = 0;
+ int r, g, b;
+
+ i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
+ i_dst_pitch = p_dst_pic->p->i_pitch;
+ p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
+ p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
+ p_dst_pic->p->i_pitch *
+ ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
+
+ p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 1 );
+ p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 2 );
+ p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 2 );
+ p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 1 );
+
+ /* Draw until we reach the bottom of the subtitle */
+ for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
+ p_dst += i_dst_pitch,
+ p_src_y += i_src_pitch, p_src_u += i_src_pitch,
+ p_src_v += i_src_pitch )
+ {
+ /* Draw until we reach the end of the line */
+ for( i_x = 0; i_x < i_width; i_x++ )
+ {
+ if( p_trans )
+ i_trans = vlc_alpha( p_trans[i_x], i_alpha );
+ if( !i_trans )
+ continue;
+
+ /* Blending */
+ yuv_to_rgb( &r, &g, &b,
+ p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
+
+ vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
+ r, g, b, i_trans, &p_filter->fmt_out.video );
+ }
+ }
+}
+
+static void BlendYUVARV24( filter_t *p_filter,
+ picture_t *p_dst_pic, const picture_t *p_src,
+ int i_x_offset, int i_y_offset,
+ int i_width, int i_height, int i_alpha )
+{
+ int i_src_pitch, i_dst_pitch;
+ uint8_t *p_dst, *p_src_y;
+ uint8_t *p_src_u, *p_src_v;
+ uint8_t *p_trans;
+ int i_x, i_y, i_pix_pitch, i_trans = 0;
+ int r, g, b;
+
+ i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
+ i_dst_pitch = p_dst_pic->p->i_pitch;
+ p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
+ p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
+ p_dst_pic->p->i_pitch *
+ ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
+
+ p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 1 );
+ p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 2 );
+ p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 2 );
+ p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 1 );
+
+ if( (i_pix_pitch == 4)
+ && (((((intptr_t)p_dst)|i_dst_pitch) /* FIXME? */
+ & 3) == 0) )
+ {
+ /*
+ ** if picture pixels are 32 bits long and lines addresses are 32 bit
+ ** aligned, optimize rendering
+ */
+ uint32_t *p32_dst = (uint32_t *)p_dst;
+ uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
+
+ int i_rshift, i_gshift, i_bshift;
+ uint32_t i_rmask, i_gmask, i_bmask;
+
+ i_rmask = p_filter->fmt_out.video.i_rmask;
+ i_gmask = p_filter->fmt_out.video.i_gmask;
+ i_bmask = p_filter->fmt_out.video.i_bmask;
+ i_rshift = p_filter->fmt_out.video.i_lrshift;
+ i_gshift = p_filter->fmt_out.video.i_lgshift;
+ i_bshift = p_filter->fmt_out.video.i_lbshift;
+
+ /* Draw until we reach the bottom of the subtitle */
+ for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
+ p32_dst += i32_dst_pitch,
+ p_src_y += i_src_pitch, p_src_u += i_src_pitch,
+ p_src_v += i_src_pitch )
+ {
+ /* Draw until we reach the end of the line */
+ for( i_x = 0; i_x < i_width; i_x++ )
+ {
+ if( p_trans )
+ i_trans = vlc_alpha( p_trans[i_x], i_alpha );
+ if( !i_trans )
+ continue;
+
+ if( i_trans == MAX_TRANS )
+ {
+ /* Completely opaque. Completely overwrite underlying pixel */
+ yuv_to_rgb( &r, &g, &b,
+ p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
+
+ p32_dst[i_x] = (r<<i_rshift) |
+ (g<<i_gshift) |
+ (b<<i_bshift);
+ }
+ else
+ {
+ /* Blending */
+ uint32_t i_pix_dst = p32_dst[i_x];
+ yuv_to_rgb( &r, &g, &b,
+ p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
+
+ p32_dst[i_x] = ( vlc_blend( r, (i_pix_dst & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
+ ( vlc_blend( g, (i_pix_dst & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
+ ( vlc_blend( b, (i_pix_dst & i_bmask)>>i_bshift, i_trans ) << i_bshift );
+ }
+ }
+ }
+ }
+ else
+ {
+ int i_rindex, i_gindex, i_bindex;
+ uint32_t i_rmask, i_gmask, i_bmask;
+
+ i_rmask = p_filter->fmt_out.video.i_rmask;
+ i_gmask = p_filter->fmt_out.video.i_gmask;
+ i_bmask = p_filter->fmt_out.video.i_bmask;
+
+ vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
+
+ /* Draw until we reach the bottom of the subtitle */
+ for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
+ p_dst += i_dst_pitch,
+ p_src_y += i_src_pitch, p_src_u += i_src_pitch,
+ p_src_v += i_src_pitch )
+ {
+ /* Draw until we reach the end of the line */
+ for( i_x = 0; i_x < i_width; i_x++ )
+ {
+ if( p_trans )
+ i_trans = vlc_alpha( p_trans[i_x], i_alpha );
+ if( !i_trans )
+ continue;
+
+ /* Blending */
+ yuv_to_rgb( &r, &g, &b,
+ p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
+
+ vlc_blend_packed( &p_dst[ i_x * i_pix_pitch],
+ i_rindex, i_gindex, i_bindex,
+ r, g, b, i_alpha, true );
+ }
+ }
+ }
+}
+
+static void BlendYUVAYUVPacked( filter_t *p_filter,
+ picture_t *p_dst_pic, const picture_t *p_src,
+ int i_x_offset, int i_y_offset,
+ int i_width, int i_height, int i_alpha )
+{
+ int i_src_pitch, i_dst_pitch;
+ uint8_t *p_dst, *p_src_y;
+ uint8_t *p_src_u, *p_src_v;
+ uint8_t *p_trans;
+ int i_x, i_y, i_pix_pitch, i_trans = 0;
+ bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
+ int i_l_offset, i_u_offset, i_v_offset;
+
+ vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
+ p_filter->fmt_out.video.i_chroma );
+
+ i_pix_pitch = 2;
+ i_dst_pitch = p_dst_pic->p->i_pitch;
+ p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
+ p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
+ p_dst_pic->p->i_pitch *
+ ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
+
+ p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 1 );
+ p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 2 );
+ p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 2 );
+ p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
+ 0, 0, &p_filter->fmt_in.video, 1 );
+
+ i_width &= ~1; /* Needs to be a multiple of 2 */
+
+ /* Draw until we reach the bottom of the subtitle */
+ for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
+ p_dst += i_dst_pitch,
+ p_src_y += i_src_pitch, p_src_u += i_src_pitch,
+ p_src_v += i_src_pitch )
+ {
+ /* Draw until we reach the end of the line */
+ for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
+ {
+ i_trans = vlc_alpha( p_trans[i_x], i_alpha );
+ if( !i_trans )
+ continue;
+
+ /* Blending */
+ if( b_even )
+ {
+ int i_u;
+ int i_v;
+ /* FIXME what's with 0xaa ? */
+ if( p_trans[i_x+1] > 0xaa )
+ {
+ i_u = (p_src_u[i_x]+p_src_u[i_x+1])>>1;
+ i_v = (p_src_v[i_x]+p_src_v[i_x+1])>>1;
+ }
+ else
+ {
+ i_u = p_src_u[i_x];
+ i_v = p_src_v[i_x];
+ }
+
+ vlc_blend_packed( &p_dst[i_x * 2],
+ i_l_offset, i_u_offset, i_v_offset,
+ p_src_y[i_x], i_u, i_v, i_trans, true );
+ }
+ else
+ {
+ 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 );
+ }
+ }
+ }
+}
+/***********************************************************************
+ * I420, YV12
+ ***********************************************************************/
+static void BlendI420I420( filter_t *p_filter,
+ picture_t *p_dst, const picture_t *p_src,
+ int i_x_offset, int i_y_offset,
+ int i_width, int i_height, int i_alpha )
+{
+ int i_src_pitch, i_dst_pitch;
+ uint8_t *p_src_y, *p_dst_y;
+ uint8_t *p_src_u, *p_dst_u;
+ uint8_t *p_src_v, *p_dst_v;
+ int i_x, i_y;
+ bool b_even_scanline = i_y_offset % 2;
+
+ if( i_alpha == 0xff )
+ {
+ BlendI420I420_no_alpha( p_filter, p_dst, p_src,
+ i_x_offset, i_y_offset, i_width, i_height );
+ return;
+ }
+