1 /*****************************************************************************
2 * blend.c: alpha blend 2 pictures together
3 *****************************************************************************
4 * Copyright (C) 2003-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
8 * Antoine Cellerier <dionoea @t videolan dot org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 static int OpenFilter ( vlc_object_t * );
41 static void CloseFilter( vlc_object_t * );
44 set_description( N_("Video pictures blending") )
45 set_capability( "video blending", 100 )
46 set_callbacks( OpenFilter, CloseFilter )
49 /****************************************************************************
51 ****************************************************************************/
52 static void Blend( filter_t *, picture_t *, const picture_t *,
56 static void BlendYUVAI420( filter_t *, picture_t *, const picture_t *,
57 int, int, int, int, int );
58 static void BlendYUVARV16( filter_t *, picture_t *, const picture_t *,
59 int, int, int, int, int );
60 static void BlendYUVARV24( filter_t *, picture_t *, const picture_t *,
61 int, int, int, int, int );
62 static void BlendYUVAYUVPacked( filter_t *, picture_t *, const picture_t *,
63 int, int, int, int, int );
66 static void BlendI420I420( filter_t *, picture_t *, const picture_t *,
67 int, int, int, int, int );
68 static void BlendI420I420_no_alpha(
69 filter_t *, picture_t *, const picture_t *,
71 static void BlendI420R16( filter_t *, picture_t *, const picture_t *,
72 int, int, int, int, int );
73 static void BlendI420R24( filter_t *, picture_t *, const picture_t *,
74 int, int, int, int, int );
75 static void BlendI420YUVPacked( filter_t *, picture_t *,
76 const picture_t *, int, int, int, int, int );
79 static void BlendPalI420( filter_t *, picture_t *, const picture_t *,
80 int, int, int, int, int );
81 static void BlendPalYUVPacked( filter_t *, picture_t *, const picture_t *,
82 int, int, int, int, int );
83 static void BlendPalRV( filter_t *, picture_t *, const picture_t *,
84 int, int, int, int, int );
87 static void BlendRGBAI420( filter_t *, picture_t *, const picture_t *,
88 int, int, int, int, int );
89 static void BlendRGBAYUVPacked( filter_t *, picture_t *,
90 const picture_t *, int, int, int, int, int );
91 static void BlendRGBAR16( filter_t *, picture_t *, const picture_t *,
92 int, int, int, int, int );
93 static void BlendRGBAR24( filter_t *, picture_t *, const picture_t *,
94 int, int, int, int, int );
101 typedef void (*BlendFunction)( filter_t *,
102 picture_t *, const picture_t *,
103 int , int , int , int , int );
105 #define VLC_CODEC_PLANAR_420 { VLC_CODEC_I420, VLC_CODEC_J420, VLC_CODEC_YV12, 0 }
106 #define VLC_CODEC_PACKED_422 { VLC_CODEC_YUYV, VLC_CODEC_UYVY, VLC_CODEC_YVYU, VLC_CODEC_VYUY, 0 }
107 #define VLC_CODEC_RGB_16 { VLC_CODEC_RGB15, VLC_CODEC_RGB16, 0 }
108 #define VLC_CODEC_RGB_24 { VLC_CODEC_RGB24, VLC_CODEC_RGB32, 0 }
110 #define BLEND_CFG( fccSrc, fctPlanar, fctPacked, fctRgb16, fctRgb24 ) \
111 { .src = fccSrc, .p_dst = VLC_CODEC_PLANAR_420, .pf_blend = fctPlanar }, \
112 { .src = fccSrc, .p_dst = VLC_CODEC_PACKED_422, .pf_blend = fctPacked }, \
113 { .src = fccSrc, .p_dst = VLC_CODEC_RGB_16, .pf_blend = fctRgb16 }, \
114 { .src = fccSrc, .p_dst = VLC_CODEC_RGB_24, .pf_blend = fctRgb24 }
119 vlc_fourcc_t p_dst[16];
120 BlendFunction pf_blend;
123 BLEND_CFG( VLC_CODEC_YUVA, BlendYUVAI420, BlendYUVAYUVPacked, BlendYUVARV16, BlendYUVARV24 ),
125 BLEND_CFG( VLC_CODEC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ),
127 BLEND_CFG( VLC_CODEC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ),
129 BLEND_CFG( VLC_CODEC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
131 BLEND_CFG( VLC_CODEC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
136 /*****************************************************************************
137 * OpenFilter: probe the filter and return score
138 *****************************************************************************/
139 static int OpenFilter( vlc_object_t *p_this )
141 filter_t *p_filter = (filter_t*)p_this;
142 filter_sys_t *p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
145 p_filter->p_sys = p_sys;
146 p_filter->p_sys->i_blendcfg = -1;
148 /* Check if we can handle that format.
149 * We could try to use a chroma filter if we can't. */
150 int in_chroma = p_filter->fmt_in.video.i_chroma;
151 int out_chroma = p_filter->fmt_out.video.i_chroma;
153 if( ( in_chroma != VLC_CODEC_YUVA && in_chroma != VLC_CODEC_I420 &&
154 in_chroma != VLC_CODEC_YV12 && in_chroma != VLC_CODEC_YUVP &&
155 in_chroma != VLC_CODEC_RGBA ) ||
156 ( out_chroma != VLC_CODEC_I420 && out_chroma != VLC_CODEC_J420 &&
157 out_chroma != VLC_CODEC_YV12 &&
158 out_chroma != VLC_CODEC_YUYV && out_chroma != VLC_CODEC_YVYU &&
159 out_chroma != VLC_CODEC_UYVY && out_chroma != VLC_CODEC_VYUY &&
160 out_chroma != VLC_CODEC_RGB15 &&
161 out_chroma != VLC_CODEC_RGB16 &&
162 out_chroma != VLC_CODEC_RGB24 &&
163 out_chroma != VLC_CODEC_RGB32 ) )
167 for( int i = 0; p_blend_cfg[i].src != 0; i++ )
169 if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma )
171 for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ )
173 if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma )
175 p_sys->i_blendcfg = i;
179 if( p_sys->i_blendcfg == -1 )
181 msg_Dbg( p_filter, "no matching alpha blending routine "
182 "(chroma: %4.4s -> %4.4s)",
183 (char *)&p_filter->fmt_in.video.i_chroma,
184 (char *)&p_filter->fmt_out.video.i_chroma );
190 p_filter->pf_video_blend = Blend;
192 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
193 (char *)&p_filter->fmt_in.video.i_chroma,
194 (char *)&p_filter->fmt_out.video.i_chroma );
199 /*****************************************************************************
200 * CloseFilter: clean up the filter
201 *****************************************************************************/
202 static void CloseFilter( vlc_object_t *p_this )
204 filter_t *p_filter = (filter_t*)p_this;
205 free( p_filter->p_sys );
208 /****************************************************************************
209 * Blend: the whole thing
210 ****************************************************************************
211 * This function is called just after the thread is launched.
212 ****************************************************************************/
214 static void Blend( filter_t *p_filter,
215 picture_t *p_dst, const picture_t *p_src,
216 int i_x_offset, int i_y_offset, int i_alpha )
218 int i_width, i_height;
223 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
224 (int)p_filter->fmt_in.video.i_visible_width);
226 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
227 (int)p_filter->fmt_in.video.i_visible_height);
229 if( i_width <= 0 || i_height <= 0 )
232 video_format_FixRgb( &p_filter->fmt_out.video );
233 video_format_FixRgb( &p_filter->fmt_in.video );
236 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
237 (char *)&p_filter->fmt_in.video.i_chroma,
238 (char *)&p_filter->fmt_out.video.i_chroma );
242 p_blend_cfg[p_filter->p_sys->i_blendcfg].pf_blend( p_filter, p_dst, p_src,
243 i_x_offset, i_y_offset,
244 i_width, i_height, i_alpha );
248 /***********************************************************************
250 ***********************************************************************/
251 static inline uint8_t vlc_uint8( int v )
260 #define MAX_TRANS 255
263 static inline int vlc_blend( int v1, int v2, int a )
265 /* TODO bench if the tests really increase speed */
268 else if( a == MAX_TRANS )
270 return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
273 static inline int vlc_alpha( int t, int a )
277 return (t * a) / 255;
280 static inline void yuv_to_rgb( int *r, int *g, int *b,
281 uint8_t y1, uint8_t u1, uint8_t v1 )
283 /* macros used for YUV pixel conversions */
284 # define SCALEBITS 10
285 # define ONE_HALF (1 << (SCALEBITS - 1))
286 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
288 int y, cb, cr, r_add, g_add, b_add;
292 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
293 g_add = - FIX(0.34414*255.0/224.0) * cb
294 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
295 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
296 y = (y1 - 16) * FIX(255.0/219.0);
297 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
298 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
299 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
305 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
306 int r, int g, int b )
308 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
309 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
310 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
313 static uint8_t *vlc_plane_start( int *pi_pitch,
314 const picture_t *p_picture,
316 int i_x_offset, int i_y_offset,
317 const video_format_t *p_fmt,
320 const int i_pitch = p_picture->p[i_plane].i_pitch;
321 uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
323 const int i_dx = ( i_x_offset + p_fmt->i_x_offset ) / r;
324 const int i_dy = ( i_y_offset + p_fmt->i_y_offset ) / r;
328 return &p_pixels[ i_dy * i_pitch + i_dx ];
331 static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma )
333 static const struct {
337 { VLC_CODEC_YUYV, 0, 1, 3 },
338 { VLC_CODEC_UYVY, 1, 0, 2 },
339 { VLC_CODEC_YVYU, 0, 3, 1 },
340 { VLC_CODEC_VYUY, 1, 2, 0 },
345 for( i = 0; p_index[i].chroma != 0; i++ )
347 if( p_index[i].chroma == i_chroma )
350 *pi_y = p_index[i].y;
351 *pi_u = p_index[i].u;
352 *pi_v = p_index[i].v;
355 static void vlc_blend_packed( uint8_t *p_dst,
356 int i_offset0, int i_offset1, int i_offset2,
357 int c0, int c1, int c2, int i_alpha,
360 p_dst[i_offset0] = vlc_blend( c0, p_dst[i_offset0], i_alpha );
363 p_dst[i_offset1] = vlc_blend( c1, p_dst[i_offset1], i_alpha );
364 p_dst[i_offset2] = vlc_blend( c2, p_dst[i_offset2], i_alpha );
368 static void vlc_blend_rgb16( uint16_t *p_dst,
369 int R, int G, int B, int i_alpha,
370 const video_format_t *p_fmt )
372 const int i_pix = *p_dst;
373 const int r = ( i_pix & p_fmt->i_rmask ) >> p_fmt->i_lrshift;
374 const int g = ( i_pix & p_fmt->i_gmask ) >> p_fmt->i_lgshift;
375 const int b = ( i_pix & p_fmt->i_bmask ) >> p_fmt->i_lbshift;
377 *p_dst = ( vlc_blend( R >> p_fmt->i_rrshift, r, i_alpha ) << p_fmt->i_lrshift ) |
378 ( vlc_blend( G >> p_fmt->i_rgshift, g, i_alpha ) << p_fmt->i_lgshift ) |
379 ( vlc_blend( B >> p_fmt->i_rbshift, b, i_alpha ) << p_fmt->i_lbshift );
382 static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex,
383 const video_format_t *p_fmt )
385 if( p_fmt->i_chroma != VLC_CODEC_RGB24 && p_fmt->i_chroma != VLC_CODEC_RGB32 )
388 /* XXX it will works only if mask are 8 bits aligned */
389 #ifdef WORDS_BIGENDIAN
390 const int i_mask_bits = p_fmt->i_chroma == VLC_CODEC_RGB24 ? 24 : 32;
391 *pi_rindex = ( i_mask_bits - p_fmt->i_lrshift ) / 8;
392 *pi_gindex = ( i_mask_bits - p_fmt->i_lgshift ) / 8;
393 *pi_bindex = ( i_mask_bits - p_fmt->i_lbshift ) / 8;
395 *pi_rindex = p_fmt->i_lrshift / 8;
396 *pi_gindex = p_fmt->i_lgshift / 8;
397 *pi_bindex = p_fmt->i_lbshift / 8;
401 /***********************************************************************
403 ***********************************************************************/
404 static void BlendYUVAI420( filter_t *p_filter,
405 picture_t *p_dst, const picture_t *p_src,
406 int i_x_offset, int i_y_offset,
407 int i_width, int i_height, int i_alpha )
409 int i_src_pitch, i_dst_pitch;
410 uint8_t *p_src_y, *p_dst_y;
411 uint8_t *p_src_u, *p_dst_u;
412 uint8_t *p_src_v, *p_dst_v;
414 int i_x, i_y, i_trans = 0;
415 bool b_even_scanline = i_y_offset % 2;
417 p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
418 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
419 p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
420 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
421 p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
422 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
424 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
425 0, 0, &p_filter->fmt_in.video, 1 );
426 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
427 0, 0, &p_filter->fmt_in.video, 2 );
428 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
429 0, 0, &p_filter->fmt_in.video, 2 );
430 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
431 0, 0, &p_filter->fmt_in.video, 1 );
433 /* Draw until we reach the bottom of the subtitle */
434 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
435 p_dst_y += i_dst_pitch, p_src_y += i_src_pitch,
436 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
437 p_src_u += i_src_pitch,
438 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
439 p_src_v += i_src_pitch )
441 b_even_scanline = !b_even_scanline;
443 /* Draw until we reach the end of the line */
444 for( i_x = 0; i_x < i_width; i_x++ )
447 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
453 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_trans );
454 if( b_even_scanline && i_x % 2 == 0 )
456 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x], p_dst_u[i_x/2], i_trans );
457 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x], p_dst_v[i_x/2], i_trans );
463 static void BlendYUVARV16( filter_t *p_filter,
464 picture_t *p_dst_pic, const picture_t *p_src,
465 int i_x_offset, int i_y_offset,
466 int i_width, int i_height, int i_alpha )
468 int i_src_pitch, i_dst_pitch;
469 uint8_t *p_dst, *p_src_y;
470 uint8_t *p_src_u, *p_src_v;
472 int i_x, i_y, i_pix_pitch, i_trans = 0;
475 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
476 i_dst_pitch = p_dst_pic->p->i_pitch;
477 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
478 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
479 p_dst_pic->p->i_pitch *
480 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
482 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
483 0, 0, &p_filter->fmt_in.video, 1 );
484 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
485 0, 0, &p_filter->fmt_in.video, 2 );
486 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
487 0, 0, &p_filter->fmt_in.video, 2 );
488 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
489 0, 0, &p_filter->fmt_in.video, 1 );
491 /* Draw until we reach the bottom of the subtitle */
492 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
493 p_dst += i_dst_pitch,
494 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
495 p_src_v += i_src_pitch )
497 /* Draw until we reach the end of the line */
498 for( i_x = 0; i_x < i_width; i_x++ )
501 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
506 yuv_to_rgb( &r, &g, &b,
507 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
509 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
510 r, g, b, i_trans, &p_filter->fmt_out.video );
515 static void BlendYUVARV24( filter_t *p_filter,
516 picture_t *p_dst_pic, const picture_t *p_src,
517 int i_x_offset, int i_y_offset,
518 int i_width, int i_height, int i_alpha )
520 int i_src_pitch, i_dst_pitch;
521 uint8_t *p_dst, *p_src_y;
522 uint8_t *p_src_u, *p_src_v;
524 int i_x, i_y, i_pix_pitch, i_trans = 0;
527 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
528 i_dst_pitch = p_dst_pic->p->i_pitch;
529 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
530 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
531 p_dst_pic->p->i_pitch *
532 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
534 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
535 0, 0, &p_filter->fmt_in.video, 1 );
536 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
537 0, 0, &p_filter->fmt_in.video, 2 );
538 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
539 0, 0, &p_filter->fmt_in.video, 2 );
540 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
541 0, 0, &p_filter->fmt_in.video, 1 );
543 if( (i_pix_pitch == 4)
544 && (((((intptr_t)p_dst)|i_dst_pitch) /* FIXME? */
548 ** if picture pixels are 32 bits long and lines addresses are 32 bit
549 ** aligned, optimize rendering
551 uint32_t *p32_dst = (uint32_t *)p_dst;
552 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
554 int i_rshift, i_gshift, i_bshift;
555 uint32_t i_rmask, i_gmask, i_bmask;
557 i_rmask = p_filter->fmt_out.video.i_rmask;
558 i_gmask = p_filter->fmt_out.video.i_gmask;
559 i_bmask = p_filter->fmt_out.video.i_bmask;
560 i_rshift = p_filter->fmt_out.video.i_lrshift;
561 i_gshift = p_filter->fmt_out.video.i_lgshift;
562 i_bshift = p_filter->fmt_out.video.i_lbshift;
564 /* Draw until we reach the bottom of the subtitle */
565 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
566 p32_dst += i32_dst_pitch,
567 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
568 p_src_v += i_src_pitch )
570 /* Draw until we reach the end of the line */
571 for( i_x = 0; i_x < i_width; i_x++ )
574 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
578 if( i_trans == MAX_TRANS )
580 /* Completely opaque. Completely overwrite underlying pixel */
581 yuv_to_rgb( &r, &g, &b,
582 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
584 p32_dst[i_x] = (r<<i_rshift) |
591 uint32_t i_pix_dst = p32_dst[i_x];
592 yuv_to_rgb( &r, &g, &b,
593 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
595 p32_dst[i_x] = ( vlc_blend( r, (i_pix_dst & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
596 ( vlc_blend( g, (i_pix_dst & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
597 ( vlc_blend( b, (i_pix_dst & i_bmask)>>i_bshift, i_trans ) << i_bshift );
604 int i_rindex, i_gindex, i_bindex;
605 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
607 /* Draw until we reach the bottom of the subtitle */
608 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
609 p_dst += i_dst_pitch,
610 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
611 p_src_v += i_src_pitch )
613 /* Draw until we reach the end of the line */
614 for( i_x = 0; i_x < i_width; i_x++ )
617 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
622 yuv_to_rgb( &r, &g, &b,
623 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
625 vlc_blend_packed( &p_dst[ i_x * i_pix_pitch],
626 i_rindex, i_gindex, i_bindex,
627 r, g, b, i_alpha, true );
633 static void BlendYUVAYUVPacked( filter_t *p_filter,
634 picture_t *p_dst_pic, const picture_t *p_src,
635 int i_x_offset, int i_y_offset,
636 int i_width, int i_height, int i_alpha )
638 int i_src_pitch, i_dst_pitch;
639 uint8_t *p_dst, *p_src_y;
640 uint8_t *p_src_u, *p_src_v;
642 int i_x, i_y, i_pix_pitch, i_trans = 0;
643 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
644 int i_l_offset, i_u_offset, i_v_offset;
646 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
647 p_filter->fmt_out.video.i_chroma );
650 i_dst_pitch = p_dst_pic->p->i_pitch;
651 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
652 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
653 p_dst_pic->p->i_pitch *
654 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
656 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
657 0, 0, &p_filter->fmt_in.video, 1 );
658 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
659 0, 0, &p_filter->fmt_in.video, 2 );
660 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
661 0, 0, &p_filter->fmt_in.video, 2 );
662 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
663 0, 0, &p_filter->fmt_in.video, 1 );
665 i_width &= ~1; /* Needs to be a multiple of 2 */
667 /* Draw until we reach the bottom of the subtitle */
668 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
669 p_dst += i_dst_pitch,
670 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
671 p_src_v += i_src_pitch )
673 /* Draw until we reach the end of the line */
674 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
676 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
685 /* FIXME what's with 0xaa ? */
686 if( p_trans[i_x+1] > 0xaa )
688 i_u = (p_src_u[i_x]+p_src_u[i_x+1])>>1;
689 i_v = (p_src_v[i_x]+p_src_v[i_x+1])>>1;
697 vlc_blend_packed( &p_dst[i_x * 2],
698 i_l_offset, i_u_offset, i_v_offset,
699 p_src_y[i_x], i_u, i_v, i_trans, true );
703 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 );
708 /***********************************************************************
710 ***********************************************************************/
711 static void BlendI420I420( filter_t *p_filter,
712 picture_t *p_dst, const picture_t *p_src,
713 int i_x_offset, int i_y_offset,
714 int i_width, int i_height, int i_alpha )
716 int i_src_pitch, i_dst_pitch;
717 uint8_t *p_src_y, *p_dst_y;
718 uint8_t *p_src_u, *p_dst_u;
719 uint8_t *p_src_v, *p_dst_v;
721 bool b_even_scanline = i_y_offset % 2;
723 if( i_alpha == 0xff )
725 BlendI420I420_no_alpha( p_filter, p_dst, p_src,
726 i_x_offset, i_y_offset, i_width, i_height );
731 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
732 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
733 p_filter->fmt_out.video.i_x_offset +
734 p_dst->p[Y_PLANE].i_pitch *
735 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
736 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
737 p_filter->fmt_out.video.i_x_offset/2 +
738 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
739 p_dst->p[U_PLANE].i_pitch;
740 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
741 p_filter->fmt_out.video.i_x_offset/2 +
742 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
743 p_dst->p[V_PLANE].i_pitch;
745 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
746 0, 0, &p_filter->fmt_in.video, 1 );
747 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
748 0, 0, &p_filter->fmt_in.video, 2 );
749 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
750 0, 0, &p_filter->fmt_in.video, 2 );
753 /* Draw until we reach the bottom of the subtitle */
754 for( i_y = 0; i_y < i_height; i_y++,
755 p_dst_y += i_dst_pitch,
756 p_src_y += i_src_pitch )
758 if( b_even_scanline )
760 p_dst_u += i_dst_pitch/2;
761 p_dst_v += i_dst_pitch/2;
763 b_even_scanline = !b_even_scanline;
765 /* Draw until we reach the end of the line */
766 for( i_x = 0; i_x < i_width; i_x++ )
772 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_alpha );
773 if( b_even_scanline && i_x % 2 == 0 )
775 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x/2], p_dst_u[i_x/2], i_alpha );
776 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x/2], p_dst_v[i_x/2], i_alpha );
781 p_src_u += i_src_pitch/2;
782 p_src_v += i_src_pitch/2;
786 static void BlendI420I420_no_alpha( filter_t *p_filter,
787 picture_t *p_dst, const picture_t *p_src,
788 int i_x_offset, int i_y_offset,
789 int i_width, int i_height )
791 int i_src_pitch, i_dst_pitch;
792 uint8_t *p_src_y, *p_dst_y;
793 uint8_t *p_src_u, *p_dst_u;
794 uint8_t *p_src_v, *p_dst_v;
796 bool b_even_scanline = i_y_offset % 2;
798 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
799 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
800 p_filter->fmt_out.video.i_x_offset +
801 p_dst->p[Y_PLANE].i_pitch *
802 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
803 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
804 p_filter->fmt_out.video.i_x_offset/2 +
805 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
806 p_dst->p[U_PLANE].i_pitch;
807 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
808 p_filter->fmt_out.video.i_x_offset/2 +
809 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
810 p_dst->p[V_PLANE].i_pitch;
812 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
813 0, 0, &p_filter->fmt_in.video, 1 );
814 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
815 0, 0, &p_filter->fmt_in.video, 2 );
816 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
817 0, 0, &p_filter->fmt_in.video, 2 );
821 /* Draw until we reach the bottom of the subtitle */
822 for( i_y = 0; i_y < i_height;
823 i_y++, p_dst_y += i_dst_pitch, p_src_y += i_src_pitch )
825 /* Completely opaque. Completely overwrite underlying pixel */
826 vlc_memcpy( p_dst_y, p_src_y, i_width );
827 if( b_even_scanline )
829 p_dst_u += i_dst_pitch/2;
830 p_dst_v += i_dst_pitch/2;
834 vlc_memcpy( p_dst_u, p_src_u, i_width/2 );
835 vlc_memcpy( p_dst_v, p_src_v, i_width/2 );
837 b_even_scanline = !b_even_scanline;
840 p_src_u += i_src_pitch/2;
841 p_src_v += i_src_pitch/2;
846 static void BlendI420R16( filter_t *p_filter,
847 picture_t *p_dst_pic, const picture_t *p_src,
848 int i_x_offset, int i_y_offset,
849 int i_width, int i_height, int i_alpha )
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;
857 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
858 i_dst_pitch = p_dst_pic->p->i_pitch;
859 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
860 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
861 p_dst_pic->p->i_pitch *
862 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
864 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
865 0, 0, &p_filter->fmt_in.video, 1 );
866 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
867 0, 0, &p_filter->fmt_in.video, 2 );
868 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
869 0, 0, &p_filter->fmt_in.video, 2 );
871 /* Draw until we reach the bottom of the subtitle */
872 for( i_y = 0; i_y < i_height; i_y++,
873 p_dst += i_dst_pitch,
874 p_src_y += i_src_pitch )
876 /* Draw until we reach the end of the line */
877 for( i_x = 0; i_x < i_width; i_x++ )
880 yuv_to_rgb( &r, &g, &b,
881 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
883 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
884 r, g, b, i_alpha, &p_filter->fmt_out.video );
888 p_src_u += i_src_pitch/2;
889 p_src_v += i_src_pitch/2;
894 static void BlendI420R24( filter_t *p_filter,
895 picture_t *p_dst_pic, const picture_t *p_src,
896 int i_x_offset, int i_y_offset,
897 int i_width, int i_height, int i_alpha )
899 int i_src_pitch, i_dst_pitch;
900 uint8_t *p_dst, *p_src_y;
901 uint8_t *p_src_u, *p_src_v;
902 int i_x, i_y, i_pix_pitch;
903 int i_rindex, i_gindex, i_bindex;
906 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
907 i_dst_pitch = p_dst_pic->p->i_pitch;
908 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
909 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
910 p_dst_pic->p->i_pitch *
911 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
913 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
914 0, 0, &p_filter->fmt_in.video, 1 );
915 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
916 0, 0, &p_filter->fmt_in.video, 2 );
917 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
918 0, 0, &p_filter->fmt_in.video, 2 );
920 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
922 /* Draw until we reach the bottom of the subtitle */
923 for( i_y = 0; i_y < i_height; i_y++,
924 p_dst += i_dst_pitch,
925 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
926 p_src_v += i_src_pitch )
928 /* Draw until we reach the end of the line */
929 for( i_x = 0; i_x < i_width; i_x++ )
935 yuv_to_rgb( &r, &g, &b,
936 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
938 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
939 i_rindex, i_gindex, i_bindex, r, g, b, i_alpha, true );
943 p_src_u += i_src_pitch/2;
944 p_src_v += i_src_pitch/2;
949 static void BlendI420YUVPacked( filter_t *p_filter,
950 picture_t *p_dst_pic, const picture_t *p_src,
951 int i_x_offset, int i_y_offset,
952 int i_width, int i_height, int i_alpha )
954 int i_src_pitch, i_dst_pitch;
955 uint8_t *p_dst, *p_src_y;
956 uint8_t *p_src_u, *p_src_v;
957 int i_x, i_y, i_pix_pitch;
958 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
959 int i_l_offset, i_u_offset, i_v_offset;
961 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
962 p_filter->fmt_out.video.i_chroma );
965 i_dst_pitch = p_dst_pic->p->i_pitch;
966 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
967 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
968 p_dst_pic->p->i_pitch *
969 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
971 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
972 0, 0, &p_filter->fmt_in.video, 1 );
973 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
974 0, 0, &p_filter->fmt_in.video, 2 );
975 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
976 0, 0, &p_filter->fmt_in.video, 2 );
978 i_width &= ~1; /* Needs to be a multiple of 2 */
980 /* Draw until we reach the bottom of the subtitle */
981 for( i_y = 0; i_y < i_height; i_y++,
982 p_dst += i_dst_pitch,
983 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
984 p_src_v += i_src_pitch )
986 /* Draw until we reach the end of the line */
987 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
993 vlc_blend_packed( &p_dst[i_x * 2],
994 i_l_offset, i_u_offset, i_v_offset,
995 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2], i_alpha, b_even );
999 p_src_u += i_src_pitch/2;
1000 p_src_v += i_src_pitch/2;
1005 /***********************************************************************
1007 ***********************************************************************/
1008 static void BlendPalI420( filter_t *p_filter,
1009 picture_t *p_dst, const picture_t *p_src_pic,
1010 int i_x_offset, int i_y_offset,
1011 int i_width, int i_height, int i_alpha )
1013 int i_src_pitch, i_dst_pitch;
1014 uint8_t *p_src, *p_dst_y;
1017 int i_x, i_y, i_trans;
1018 bool b_even_scanline = i_y_offset % 2;
1020 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1021 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1022 p_filter->fmt_out.video.i_x_offset +
1023 p_dst->p[Y_PLANE].i_pitch *
1024 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1025 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1026 p_filter->fmt_out.video.i_x_offset/2 +
1027 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1028 p_dst->p[U_PLANE].i_pitch;
1029 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1030 p_filter->fmt_out.video.i_x_offset/2 +
1031 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1032 p_dst->p[V_PLANE].i_pitch;
1034 i_src_pitch = p_src_pic->p->i_pitch;
1035 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1036 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1038 #define p_pal p_filter->fmt_in.video.p_palette->palette
1040 /* Draw until we reach the bottom of the subtitle */
1041 for( i_y = 0; i_y < i_height; i_y++,
1042 p_dst_y += i_dst_pitch,
1043 p_src += i_src_pitch,
1044 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1045 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0 )
1047 const uint8_t *p_trans = p_src;
1048 b_even_scanline = !b_even_scanline;
1050 /* Draw until we reach the end of the line */
1051 for( i_x = 0; i_x < i_width; i_x++ )
1053 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1058 p_dst_y[i_x] = vlc_blend( p_pal[p_src[i_x]][0], p_dst_y[i_x], i_trans );
1059 if( b_even_scanline && ((i_x % 2) == 0) )
1061 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src[i_x]][1], p_dst_u[i_x/2], i_trans );
1062 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src[i_x]][2], p_dst_v[i_x/2], i_trans );
1069 static void BlendPalYUVPacked( filter_t *p_filter,
1070 picture_t *p_dst_pic, const picture_t *p_src_pic,
1071 int i_x_offset, int i_y_offset,
1072 int i_width, int i_height, int i_alpha )
1074 int i_src_pitch, i_dst_pitch;
1075 uint8_t *p_src, *p_dst;
1076 int i_x, i_y, i_pix_pitch, i_trans;
1077 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1078 int i_l_offset, i_u_offset, i_v_offset;
1080 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1081 p_filter->fmt_out.video.i_chroma );
1084 i_dst_pitch = p_dst_pic->p->i_pitch;
1085 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1086 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1087 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1089 i_src_pitch = p_src_pic->p->i_pitch;
1090 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1091 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1093 i_width &= ~1; /* Needs to be a multiple of 2 */
1095 #define p_pal p_filter->fmt_in.video.p_palette->palette
1097 /* Draw until we reach the bottom of the subtitle */
1098 for( i_y = 0; i_y < i_height; i_y++,
1099 p_dst += i_dst_pitch, p_src += i_src_pitch )
1101 const uint8_t *p_trans = p_src;
1102 /* Draw until we reach the end of the line */
1103 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1105 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1114 if( p_trans[i_x+1] > 0xaa )
1116 i_u = (p_pal[p_src[i_x]][1] + p_pal[p_src[i_x+1]][1]) >> 1;
1117 i_v = (p_pal[p_src[i_x]][2] + p_pal[p_src[i_x+1]][2]) >> 1;
1121 i_u = p_pal[p_src[i_x]][1];
1122 i_v = p_pal[p_src[i_x]][2];
1125 vlc_blend_packed( &p_dst[i_x * 2],
1126 i_l_offset, i_u_offset, i_v_offset,
1127 p_pal[p_src[i_x]][0], i_u, i_v, i_trans, true );
1131 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 );
1138 static void BlendPalRV( filter_t *p_filter,
1139 picture_t *p_dst_pic, const picture_t *p_src_pic,
1140 int i_x_offset, int i_y_offset,
1141 int i_width, int i_height, int i_alpha )
1143 int i_src_pitch, i_dst_pitch;
1144 uint8_t *p_src, *p_dst;
1145 int i_x, i_y, i_pix_pitch, i_trans;
1146 video_palette_t rgbpalette;
1147 int i_rindex, i_gindex, i_bindex;
1149 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1150 i_dst_pitch = p_dst_pic->p->i_pitch;
1151 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1152 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1153 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1155 i_src_pitch = p_src_pic->p->i_pitch;
1156 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1157 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1159 #define p_pal p_filter->fmt_in.video.p_palette->palette
1160 #define rgbpal rgbpalette.palette
1162 /* Convert palette first */
1163 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && i_y < 256; i_y++ )
1167 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1174 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1176 /* Draw until we reach the bottom of the subtitle */
1177 for( i_y = 0; i_y < i_height; i_y++,
1178 p_dst += i_dst_pitch, p_src += i_src_pitch )
1180 const uint8_t *p_trans = p_src;
1181 /* Draw until we reach the end of the line */
1182 for( i_x = 0; i_x < i_width; i_x++ )
1184 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1189 if( p_filter->fmt_out.video.i_chroma == VLC_CODEC_RGB15 || p_filter->fmt_out.video.i_chroma == VLC_CODEC_RGB16 )
1190 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1191 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1193 &p_filter->fmt_out.video );
1195 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1196 i_rindex, i_gindex, i_bindex,
1197 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1206 /***********************************************************************
1208 ***********************************************************************/
1209 static void BlendRGBAI420( filter_t *p_filter,
1210 picture_t *p_dst, const picture_t *p_src_pic,
1211 int i_x_offset, int i_y_offset,
1212 int i_width, int i_height, int i_alpha )
1214 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1219 int i_x, i_y, i_trans;
1222 bool b_even_scanline = i_y_offset % 2;
1224 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1225 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1226 p_filter->fmt_out.video.i_x_offset +
1227 p_dst->p[Y_PLANE].i_pitch *
1228 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1229 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1230 p_filter->fmt_out.video.i_x_offset/2 +
1231 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1232 p_dst->p[U_PLANE].i_pitch;
1233 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1234 p_filter->fmt_out.video.i_x_offset/2 +
1235 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1236 p_dst->p[V_PLANE].i_pitch;
1238 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1239 i_src_pitch = p_src_pic->p->i_pitch;
1240 p_src = p_src_pic->p->p_pixels +
1241 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1242 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1245 /* Draw until we reach the bottom of the subtitle */
1246 for( i_y = 0; i_y < i_height; i_y++,
1247 p_dst_y += i_dst_pitch,
1248 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1249 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1250 p_src += i_src_pitch )
1252 b_even_scanline = !b_even_scanline;
1254 /* Draw until we reach the end of the line */
1255 for( i_x = 0; i_x < i_width; i_x++ )
1257 const int R = p_src[i_x * i_src_pix_pitch + 0];
1258 const int G = p_src[i_x * i_src_pix_pitch + 1];
1259 const int B = p_src[i_x * i_src_pix_pitch + 2];
1261 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1266 rgb_to_yuv( &y, &u, &v, R, G, B );
1268 p_dst_y[i_x] = vlc_blend( y, p_dst_y[i_x], i_trans );
1269 if( b_even_scanline && i_x % 2 == 0 )
1271 p_dst_u[i_x/2] = vlc_blend( u, p_dst_u[i_x/2], i_trans );
1272 p_dst_v[i_x/2] = vlc_blend( v, p_dst_v[i_x/2], i_trans );
1278 static void BlendRGBAR24( filter_t *p_filter,
1279 picture_t *p_dst_pic, const picture_t *p_src_pic,
1280 int i_x_offset, int i_y_offset,
1281 int i_width, int i_height, int i_alpha )
1283 int i_src_pitch, i_dst_pitch;
1284 uint8_t *p_dst, *p_src;
1285 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1286 int i_rindex, i_gindex, i_bindex;
1288 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1289 i_dst_pitch = p_dst_pic->p->i_pitch;
1290 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1291 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1292 p_dst_pic->p->i_pitch *
1293 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1295 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1296 i_src_pitch = p_src_pic->p->i_pitch;
1297 p_src = p_src_pic->p->p_pixels +
1298 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1299 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1301 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1303 /* Draw until we reach the bottom of the subtitle */
1304 for( i_y = 0; i_y < i_height; i_y++,
1305 p_dst += i_dst_pitch, p_src += i_src_pitch )
1307 /* Draw until we reach the end of the line */
1308 for( i_x = 0; i_x < i_width; i_x++ )
1310 const int R = p_src[i_x * i_src_pix_pitch + 0];
1311 const int G = p_src[i_x * i_src_pix_pitch + 1];
1312 const int B = p_src[i_x * i_src_pix_pitch + 2];
1314 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1319 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1320 i_rindex, i_gindex, i_bindex,
1321 R, G, B, i_trans, true );
1326 static void BlendRGBAR16( filter_t *p_filter,
1327 picture_t *p_dst_pic, const picture_t *p_src_pic,
1328 int i_x_offset, int i_y_offset,
1329 int i_width, int i_height, int i_alpha )
1331 int i_src_pitch, i_dst_pitch;
1332 uint8_t *p_dst, *p_src;
1333 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1335 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1336 i_dst_pitch = p_dst_pic->p->i_pitch;
1337 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1338 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1339 p_dst_pic->p->i_pitch *
1340 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1342 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1343 i_src_pitch = p_src_pic->p->i_pitch;
1344 p_src = p_src_pic->p->p_pixels +
1345 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1346 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1348 /* Draw until we reach the bottom of the subtitle */
1349 for( i_y = 0; i_y < i_height; i_y++,
1350 p_dst += i_dst_pitch, p_src += i_src_pitch )
1352 /* Draw until we reach the end of the line */
1353 for( i_x = 0; i_x < i_width; i_x++ )
1355 const int R = p_src[i_x * i_src_pix_pitch + 0];
1356 const int G = p_src[i_x * i_src_pix_pitch + 1];
1357 const int B = p_src[i_x * i_src_pix_pitch + 2];
1359 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1364 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1365 R, G, B, i_trans, &p_filter->fmt_out.video );
1370 static void BlendRGBAYUVPacked( filter_t *p_filter,
1371 picture_t *p_dst_pic, const picture_t *p_src_pic,
1372 int i_x_offset, int i_y_offset,
1373 int i_width, int i_height, int i_alpha )
1375 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1376 uint8_t *p_dst, *p_src;
1377 int i_x, i_y, i_pix_pitch, i_trans;
1378 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1379 int i_l_offset, i_u_offset, i_v_offset;
1382 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1383 p_filter->fmt_out.video.i_chroma );
1386 i_dst_pitch = p_dst_pic->p->i_pitch;
1387 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1388 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1389 p_dst_pic->p->i_pitch *
1390 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1392 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1393 i_src_pitch = p_src_pic->p->i_pitch;
1394 p_src = p_src_pic->p->p_pixels +
1395 p_filter->fmt_in.video.i_x_offset * i_src_pitch +
1396 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1398 i_width &= ~1; /* Needs to be a multiple of 2 */
1400 /* Draw until we reach the bottom of the subtitle */
1401 for( i_y = 0; i_y < i_height; i_y++,
1402 p_dst += i_dst_pitch,
1403 p_src += i_src_pitch )
1405 /* Draw until we reach the end of the line */
1406 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1408 const int R = p_src[i_x * i_src_pix_pitch + 0];
1409 const int G = p_src[i_x * i_src_pix_pitch + 1];
1410 const int B = p_src[i_x * i_src_pix_pitch + 2];
1412 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1417 rgb_to_yuv( &y, &u, &v, R, G, B );
1419 vlc_blend_packed( &p_dst[i_x * 2],
1420 i_l_offset, i_u_offset, i_v_offset,
1421 y, u, v, i_trans, b_even );