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 );
96 /*****************************************************************************
97 * OpenFilter: probe the filter and return score
98 *****************************************************************************/
99 static int OpenFilter( vlc_object_t *p_this )
101 filter_t *p_filter = (filter_t*)p_this;
103 /* Check if we can handle that format.
104 * We could try to use a chroma filter if we can't. */
105 int in_chroma = p_filter->fmt_in.video.i_chroma;
106 int out_chroma = p_filter->fmt_out.video.i_chroma;
107 if( ( in_chroma != VLC_CODEC_YUVA && in_chroma != VLC_CODEC_I420 &&
108 in_chroma != VLC_CODEC_YV12 && in_chroma != VLC_CODEC_YUVP &&
109 in_chroma != VLC_CODEC_RGBA ) ||
110 ( out_chroma != VLC_CODEC_I420 && out_chroma != VLC_CODEC_J420 &&
111 out_chroma != VLC_CODEC_YV12 &&
112 out_chroma != VLC_CODEC_YUYV && out_chroma != VLC_CODEC_YVYU &&
113 out_chroma != VLC_CODEC_UYVY && out_chroma != VLC_CODEC_VYUY &&
114 out_chroma != VLC_CODEC_RGB15 &&
115 out_chroma != VLC_CODEC_RGB16 &&
116 out_chroma != VLC_CODEC_RGB24 &&
117 out_chroma != VLC_CODEC_RGB32 ) )
123 p_filter->pf_video_blend = Blend;
125 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
126 (char *)&p_filter->fmt_in.video.i_chroma,
127 (char *)&p_filter->fmt_out.video.i_chroma );
132 /*****************************************************************************
133 * CloseFilter: clean up the filter
134 *****************************************************************************/
135 static void CloseFilter( vlc_object_t *p_this )
140 /****************************************************************************
141 * Blend: the whole thing
142 ****************************************************************************
143 * This function is called just after the thread is launched.
144 ****************************************************************************/
145 typedef void (*BlendFunction)( filter_t *,
146 picture_t *, const picture_t *,
147 int , int , int , int , int );
149 #define VLC_CODEC_PLANAR_420 { VLC_CODEC_I420, VLC_CODEC_J420, VLC_CODEC_YV12, 0 }
150 #define VLC_CODEC_PACKED_422 { VLC_CODEC_YUYV, VLC_CODEC_UYVY, VLC_CODEC_YVYU, VLC_CODEC_VYUY, 0 }
151 #define VLC_CODEC_RGB_16 { VLC_CODEC_RGB15, VLC_CODEC_RGB16, 0 }
152 #define VLC_CODEC_RGB_24 { VLC_CODEC_RGB24, VLC_CODEC_RGB32, 0 }
154 #define BLEND_CFG( fccSrc, fctPlanar, fctPacked, fctRgb16, fctRgb24 ) \
155 { .src = fccSrc, .p_dst = VLC_CODEC_PLANAR_420, .pf_blend = fctPlanar }, \
156 { .src = fccSrc, .p_dst = VLC_CODEC_PACKED_422, .pf_blend = fctPacked }, \
157 { .src = fccSrc, .p_dst = VLC_CODEC_RGB_16, .pf_blend = fctRgb16 }, \
158 { .src = fccSrc, .p_dst = VLC_CODEC_RGB_24, .pf_blend = fctRgb24 }
163 vlc_fourcc_t p_dst[16];
164 BlendFunction pf_blend;
167 BLEND_CFG( VLC_CODEC_YUVA, BlendYUVAI420, BlendYUVAYUVPacked, BlendYUVARV16, BlendYUVARV24 ),
169 BLEND_CFG( VLC_CODEC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ),
171 BLEND_CFG( VLC_CODEC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ),
173 BLEND_CFG( VLC_CODEC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
175 BLEND_CFG( VLC_CODEC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
180 static void Blend( filter_t *p_filter,
181 picture_t *p_dst, const picture_t *p_src,
182 int i_x_offset, int i_y_offset, int i_alpha )
184 int i_width, i_height;
189 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
190 (int)p_filter->fmt_in.video.i_visible_width);
192 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
193 (int)p_filter->fmt_in.video.i_visible_height);
195 if( i_width <= 0 || i_height <= 0 )
198 video_format_FixRgb( &p_filter->fmt_out.video );
199 video_format_FixRgb( &p_filter->fmt_in.video );
202 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
203 (char *)&p_filter->fmt_in.video.i_chroma,
204 (char *)&p_filter->fmt_out.video.i_chroma );
207 for( int i = 0; p_blend_cfg[i].src != 0; i++ )
209 if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma )
211 for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ )
213 if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma )
216 p_blend_cfg[i].pf_blend( p_filter, p_dst, p_src,
217 i_x_offset, i_y_offset,
218 i_width, i_height, i_alpha );
223 msg_Dbg( p_filter, "no matching alpha blending routine "
224 "(chroma: %4.4s -> %4.4s)",
225 (char *)&p_filter->fmt_in.video.i_chroma,
226 (char *)&p_filter->fmt_out.video.i_chroma );
229 /***********************************************************************
231 ***********************************************************************/
232 static inline uint8_t vlc_uint8( int v )
241 #define MAX_TRANS 255
244 static inline int vlc_blend( int v1, int v2, int a )
246 /* TODO bench if the tests really increase speed */
249 else if( a == MAX_TRANS )
251 return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
254 static inline int vlc_alpha( int t, int a )
258 return (t * a) / 255;
261 static inline void yuv_to_rgb( int *r, int *g, int *b,
262 uint8_t y1, uint8_t u1, uint8_t v1 )
264 /* macros used for YUV pixel conversions */
265 # define SCALEBITS 10
266 # define ONE_HALF (1 << (SCALEBITS - 1))
267 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
269 int y, cb, cr, r_add, g_add, b_add;
273 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
274 g_add = - FIX(0.34414*255.0/224.0) * cb
275 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
276 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
277 y = (y1 - 16) * FIX(255.0/219.0);
278 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
279 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
280 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
286 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
287 int r, int g, int b )
289 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
290 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
291 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
294 static uint8_t *vlc_plane_start( int *pi_pitch,
295 const picture_t *p_picture,
297 int i_x_offset, int i_y_offset,
298 const video_format_t *p_fmt,
301 const int i_pitch = p_picture->p[i_plane].i_pitch;
302 uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
304 const int i_dx = ( i_x_offset + p_fmt->i_x_offset ) / r;
305 const int i_dy = ( i_y_offset + p_fmt->i_y_offset ) / r;
309 return &p_pixels[ i_dy * i_pitch + i_dx ];
312 static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma )
314 static const struct {
318 { VLC_CODEC_YUYV, 0, 1, 3 },
319 { VLC_CODEC_UYVY, 1, 0, 2 },
320 { VLC_CODEC_YVYU, 0, 3, 1 },
321 { VLC_CODEC_VYUY, 1, 2, 0 },
326 for( i = 0; p_index[i].chroma != 0; i++ )
328 if( p_index[i].chroma == i_chroma )
331 *pi_y = p_index[i].y;
332 *pi_u = p_index[i].u;
333 *pi_v = p_index[i].v;
336 static void vlc_blend_packed( uint8_t *p_dst,
337 int i_offset0, int i_offset1, int i_offset2,
338 int c0, int c1, int c2, int i_alpha,
341 p_dst[i_offset0] = vlc_blend( c0, p_dst[i_offset0], i_alpha );
344 p_dst[i_offset1] = vlc_blend( c1, p_dst[i_offset1], i_alpha );
345 p_dst[i_offset2] = vlc_blend( c2, p_dst[i_offset2], i_alpha );
349 static void vlc_blend_rgb16( uint16_t *p_dst,
350 int R, int G, int B, int i_alpha,
351 const video_format_t *p_fmt )
353 const int i_pix = *p_dst;
354 const int r = ( i_pix & p_fmt->i_rmask ) >> p_fmt->i_lrshift;
355 const int g = ( i_pix & p_fmt->i_gmask ) >> p_fmt->i_lgshift;
356 const int b = ( i_pix & p_fmt->i_bmask ) >> p_fmt->i_lbshift;
358 *p_dst = ( vlc_blend( R >> p_fmt->i_rrshift, r, i_alpha ) << p_fmt->i_lrshift ) |
359 ( vlc_blend( G >> p_fmt->i_rgshift, g, i_alpha ) << p_fmt->i_lgshift ) |
360 ( vlc_blend( B >> p_fmt->i_rbshift, b, i_alpha ) << p_fmt->i_lbshift );
363 static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex,
364 const video_format_t *p_fmt )
366 if( p_fmt->i_chroma != VLC_CODEC_RGB24 && p_fmt->i_chroma != VLC_CODEC_RGB32 )
369 /* XXX it will works only if mask are 8 bits aligned */
370 #ifdef WORDS_BIGENDIAN
371 const int i_mask_bits = p_fmt->i_chroma == VLC_CODEC_RGB24 ? 24 : 32;
372 *pi_rindex = ( i_mask_bits - p_fmt->i_lrshift ) / 8;
373 *pi_gindex = ( i_mask_bits - p_fmt->i_lgshift ) / 8;
374 *pi_bindex = ( i_mask_bits - p_fmt->i_lbshift ) / 8;
376 *pi_rindex = p_fmt->i_lrshift / 8;
377 *pi_gindex = p_fmt->i_lgshift / 8;
378 *pi_bindex = p_fmt->i_lbshift / 8;
382 /***********************************************************************
384 ***********************************************************************/
385 static void BlendYUVAI420( filter_t *p_filter,
386 picture_t *p_dst, const picture_t *p_src,
387 int i_x_offset, int i_y_offset,
388 int i_width, int i_height, int i_alpha )
390 int i_src_pitch, i_dst_pitch;
391 uint8_t *p_src_y, *p_dst_y;
392 uint8_t *p_src_u, *p_dst_u;
393 uint8_t *p_src_v, *p_dst_v;
395 int i_x, i_y, i_trans = 0;
396 bool b_even_scanline = i_y_offset % 2;
398 p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
399 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
400 p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
401 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
402 p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
403 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
405 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
406 0, 0, &p_filter->fmt_in.video, 1 );
407 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
408 0, 0, &p_filter->fmt_in.video, 2 );
409 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
410 0, 0, &p_filter->fmt_in.video, 2 );
411 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
412 0, 0, &p_filter->fmt_in.video, 1 );
414 /* Draw until we reach the bottom of the subtitle */
415 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
416 p_dst_y += i_dst_pitch, p_src_y += i_src_pitch,
417 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
418 p_src_u += i_src_pitch,
419 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
420 p_src_v += i_src_pitch )
422 b_even_scanline = !b_even_scanline;
424 /* Draw until we reach the end of the line */
425 for( i_x = 0; i_x < i_width; i_x++ )
428 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
434 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_trans );
435 if( b_even_scanline && i_x % 2 == 0 )
437 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x], p_dst_u[i_x/2], i_trans );
438 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x], p_dst_v[i_x/2], i_trans );
444 static void BlendYUVARV16( filter_t *p_filter,
445 picture_t *p_dst_pic, const picture_t *p_src,
446 int i_x_offset, int i_y_offset,
447 int i_width, int i_height, int i_alpha )
449 int i_src_pitch, i_dst_pitch;
450 uint8_t *p_dst, *p_src_y;
451 uint8_t *p_src_u, *p_src_v;
453 int i_x, i_y, i_pix_pitch, i_trans = 0;
456 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
457 i_dst_pitch = p_dst_pic->p->i_pitch;
458 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
459 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
460 p_dst_pic->p->i_pitch *
461 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
463 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
464 0, 0, &p_filter->fmt_in.video, 1 );
465 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
466 0, 0, &p_filter->fmt_in.video, 2 );
467 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
468 0, 0, &p_filter->fmt_in.video, 2 );
469 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
470 0, 0, &p_filter->fmt_in.video, 1 );
472 /* Draw until we reach the bottom of the subtitle */
473 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
474 p_dst += i_dst_pitch,
475 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
476 p_src_v += i_src_pitch )
478 /* Draw until we reach the end of the line */
479 for( i_x = 0; i_x < i_width; i_x++ )
482 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
487 yuv_to_rgb( &r, &g, &b,
488 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
490 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
491 r, g, b, i_trans, &p_filter->fmt_out.video );
496 static void BlendYUVARV24( filter_t *p_filter,
497 picture_t *p_dst_pic, const picture_t *p_src,
498 int i_x_offset, int i_y_offset,
499 int i_width, int i_height, int i_alpha )
501 int i_src_pitch, i_dst_pitch;
502 uint8_t *p_dst, *p_src_y;
503 uint8_t *p_src_u, *p_src_v;
505 int i_x, i_y, i_pix_pitch, i_trans = 0;
508 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
509 i_dst_pitch = p_dst_pic->p->i_pitch;
510 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
511 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
512 p_dst_pic->p->i_pitch *
513 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
515 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
516 0, 0, &p_filter->fmt_in.video, 1 );
517 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
518 0, 0, &p_filter->fmt_in.video, 2 );
519 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
520 0, 0, &p_filter->fmt_in.video, 2 );
521 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
522 0, 0, &p_filter->fmt_in.video, 1 );
524 if( (i_pix_pitch == 4)
525 && (((((intptr_t)p_dst)|i_dst_pitch) /* FIXME? */
529 ** if picture pixels are 32 bits long and lines addresses are 32 bit
530 ** aligned, optimize rendering
532 uint32_t *p32_dst = (uint32_t *)p_dst;
533 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
535 int i_rshift, i_gshift, i_bshift;
536 uint32_t i_rmask, i_gmask, i_bmask;
538 i_rmask = p_filter->fmt_out.video.i_rmask;
539 i_gmask = p_filter->fmt_out.video.i_gmask;
540 i_bmask = p_filter->fmt_out.video.i_bmask;
541 i_rshift = p_filter->fmt_out.video.i_lrshift;
542 i_gshift = p_filter->fmt_out.video.i_lgshift;
543 i_bshift = p_filter->fmt_out.video.i_lbshift;
545 /* Draw until we reach the bottom of the subtitle */
546 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
547 p32_dst += i32_dst_pitch,
548 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
549 p_src_v += i_src_pitch )
551 /* Draw until we reach the end of the line */
552 for( i_x = 0; i_x < i_width; i_x++ )
555 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
559 if( i_trans == MAX_TRANS )
561 /* Completely opaque. Completely overwrite underlying pixel */
562 yuv_to_rgb( &r, &g, &b,
563 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
565 p32_dst[i_x] = (r<<i_rshift) |
572 uint32_t i_pix_dst = p32_dst[i_x];
573 yuv_to_rgb( &r, &g, &b,
574 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
576 p32_dst[i_x] = ( vlc_blend( r, (i_pix_dst & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
577 ( vlc_blend( g, (i_pix_dst & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
578 ( vlc_blend( b, (i_pix_dst & i_bmask)>>i_bshift, i_trans ) << i_bshift );
585 int i_rindex, i_gindex, i_bindex;
586 uint32_t i_rmask, i_gmask, i_bmask;
588 i_rmask = p_filter->fmt_out.video.i_rmask;
589 i_gmask = p_filter->fmt_out.video.i_gmask;
590 i_bmask = p_filter->fmt_out.video.i_bmask;
592 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
594 /* Draw until we reach the bottom of the subtitle */
595 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
596 p_dst += i_dst_pitch,
597 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
598 p_src_v += i_src_pitch )
600 /* Draw until we reach the end of the line */
601 for( i_x = 0; i_x < i_width; i_x++ )
604 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
609 yuv_to_rgb( &r, &g, &b,
610 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
612 vlc_blend_packed( &p_dst[ i_x * i_pix_pitch],
613 i_rindex, i_gindex, i_bindex,
614 r, g, b, i_alpha, true );
620 static void BlendYUVAYUVPacked( filter_t *p_filter,
621 picture_t *p_dst_pic, const picture_t *p_src,
622 int i_x_offset, int i_y_offset,
623 int i_width, int i_height, int i_alpha )
625 int i_src_pitch, i_dst_pitch;
626 uint8_t *p_dst, *p_src_y;
627 uint8_t *p_src_u, *p_src_v;
629 int i_x, i_y, i_pix_pitch, i_trans = 0;
630 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
631 int i_l_offset, i_u_offset, i_v_offset;
633 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
634 p_filter->fmt_out.video.i_chroma );
637 i_dst_pitch = p_dst_pic->p->i_pitch;
638 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
639 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
640 p_dst_pic->p->i_pitch *
641 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
643 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
644 0, 0, &p_filter->fmt_in.video, 1 );
645 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
646 0, 0, &p_filter->fmt_in.video, 2 );
647 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
648 0, 0, &p_filter->fmt_in.video, 2 );
649 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
650 0, 0, &p_filter->fmt_in.video, 1 );
652 i_width &= ~1; /* Needs to be a multiple of 2 */
654 /* Draw until we reach the bottom of the subtitle */
655 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
656 p_dst += i_dst_pitch,
657 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
658 p_src_v += i_src_pitch )
660 /* Draw until we reach the end of the line */
661 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
663 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
672 /* FIXME what's with 0xaa ? */
673 if( p_trans[i_x+1] > 0xaa )
675 i_u = (p_src_u[i_x]+p_src_u[i_x+1])>>1;
676 i_v = (p_src_v[i_x]+p_src_v[i_x+1])>>1;
684 vlc_blend_packed( &p_dst[i_x * 2],
685 i_l_offset, i_u_offset, i_v_offset,
686 p_src_y[i_x], i_u, i_v, i_trans, true );
690 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 );
695 /***********************************************************************
697 ***********************************************************************/
698 static void BlendI420I420( filter_t *p_filter,
699 picture_t *p_dst, const picture_t *p_src,
700 int i_x_offset, int i_y_offset,
701 int i_width, int i_height, int i_alpha )
703 int i_src_pitch, i_dst_pitch;
704 uint8_t *p_src_y, *p_dst_y;
705 uint8_t *p_src_u, *p_dst_u;
706 uint8_t *p_src_v, *p_dst_v;
708 bool b_even_scanline = i_y_offset % 2;
710 if( i_alpha == 0xff )
712 BlendI420I420_no_alpha( p_filter, p_dst, p_src,
713 i_x_offset, i_y_offset, i_width, i_height );
718 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
719 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
720 p_filter->fmt_out.video.i_x_offset +
721 p_dst->p[Y_PLANE].i_pitch *
722 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
723 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
724 p_filter->fmt_out.video.i_x_offset/2 +
725 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
726 p_dst->p[U_PLANE].i_pitch;
727 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
728 p_filter->fmt_out.video.i_x_offset/2 +
729 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
730 p_dst->p[V_PLANE].i_pitch;
732 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
733 0, 0, &p_filter->fmt_in.video, 1 );
734 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
735 0, 0, &p_filter->fmt_in.video, 2 );
736 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
737 0, 0, &p_filter->fmt_in.video, 2 );
740 /* Draw until we reach the bottom of the subtitle */
741 for( i_y = 0; i_y < i_height; i_y++,
742 p_dst_y += i_dst_pitch,
743 p_src_y += i_src_pitch )
745 if( b_even_scanline )
747 p_dst_u += i_dst_pitch/2;
748 p_dst_v += i_dst_pitch/2;
750 b_even_scanline = !b_even_scanline;
752 /* Draw until we reach the end of the line */
753 for( i_x = 0; i_x < i_width; i_x++ )
759 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_alpha );
760 if( b_even_scanline && i_x % 2 == 0 )
762 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x/2], p_dst_u[i_x/2], i_alpha );
763 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x/2], p_dst_v[i_x/2], i_alpha );
768 p_src_u += i_src_pitch/2;
769 p_src_v += i_src_pitch/2;
773 static void BlendI420I420_no_alpha( filter_t *p_filter,
774 picture_t *p_dst, const picture_t *p_src,
775 int i_x_offset, int i_y_offset,
776 int i_width, int i_height )
778 int i_src_pitch, i_dst_pitch;
779 uint8_t *p_src_y, *p_dst_y;
780 uint8_t *p_src_u, *p_dst_u;
781 uint8_t *p_src_v, *p_dst_v;
783 bool b_even_scanline = i_y_offset % 2;
785 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
786 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
787 p_filter->fmt_out.video.i_x_offset +
788 p_dst->p[Y_PLANE].i_pitch *
789 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
790 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
791 p_filter->fmt_out.video.i_x_offset/2 +
792 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
793 p_dst->p[U_PLANE].i_pitch;
794 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
795 p_filter->fmt_out.video.i_x_offset/2 +
796 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
797 p_dst->p[V_PLANE].i_pitch;
799 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
800 0, 0, &p_filter->fmt_in.video, 1 );
801 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
802 0, 0, &p_filter->fmt_in.video, 2 );
803 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
804 0, 0, &p_filter->fmt_in.video, 2 );
808 /* Draw until we reach the bottom of the subtitle */
809 for( i_y = 0; i_y < i_height;
810 i_y++, p_dst_y += i_dst_pitch, p_src_y += i_src_pitch )
812 /* Completely opaque. Completely overwrite underlying pixel */
813 vlc_memcpy( p_dst_y, p_src_y, i_width );
814 if( b_even_scanline )
816 p_dst_u += i_dst_pitch/2;
817 p_dst_v += i_dst_pitch/2;
821 vlc_memcpy( p_dst_u, p_src_u, i_width/2 );
822 vlc_memcpy( p_dst_v, p_src_v, i_width/2 );
824 b_even_scanline = !b_even_scanline;
827 p_src_u += i_src_pitch/2;
828 p_src_v += i_src_pitch/2;
833 static void BlendI420R16( filter_t *p_filter,
834 picture_t *p_dst_pic, const picture_t *p_src,
835 int i_x_offset, int i_y_offset,
836 int i_width, int i_height, int i_alpha )
838 int i_src_pitch, i_dst_pitch;
839 uint8_t *p_dst, *p_src_y;
840 uint8_t *p_src_u, *p_src_v;
841 int i_x, i_y, i_pix_pitch;
844 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
845 i_dst_pitch = p_dst_pic->p->i_pitch;
846 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
847 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
848 p_dst_pic->p->i_pitch *
849 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
851 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
852 0, 0, &p_filter->fmt_in.video, 1 );
853 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
854 0, 0, &p_filter->fmt_in.video, 2 );
855 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
856 0, 0, &p_filter->fmt_in.video, 2 );
858 /* Draw until we reach the bottom of the subtitle */
859 for( i_y = 0; i_y < i_height; i_y++,
860 p_dst += i_dst_pitch,
861 p_src_y += i_src_pitch )
863 /* Draw until we reach the end of the line */
864 for( i_x = 0; i_x < i_width; i_x++ )
867 yuv_to_rgb( &r, &g, &b,
868 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
870 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
871 r, g, b, i_alpha, &p_filter->fmt_out.video );
875 p_src_u += i_src_pitch/2;
876 p_src_v += i_src_pitch/2;
881 static void BlendI420R24( filter_t *p_filter,
882 picture_t *p_dst_pic, const picture_t *p_src,
883 int i_x_offset, int i_y_offset,
884 int i_width, int i_height, int i_alpha )
886 int i_src_pitch, i_dst_pitch;
887 uint8_t *p_dst, *p_src_y;
888 uint8_t *p_src_u, *p_src_v;
889 int i_x, i_y, i_pix_pitch;
890 int i_rindex, i_gindex, i_bindex;
893 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
894 i_dst_pitch = p_dst_pic->p->i_pitch;
895 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
896 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
897 p_dst_pic->p->i_pitch *
898 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
900 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
901 0, 0, &p_filter->fmt_in.video, 1 );
902 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
903 0, 0, &p_filter->fmt_in.video, 2 );
904 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
905 0, 0, &p_filter->fmt_in.video, 2 );
907 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
909 /* Draw until we reach the bottom of the subtitle */
910 for( i_y = 0; i_y < i_height; i_y++,
911 p_dst += i_dst_pitch,
912 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
913 p_src_v += i_src_pitch )
915 /* Draw until we reach the end of the line */
916 for( i_x = 0; i_x < i_width; i_x++ )
922 yuv_to_rgb( &r, &g, &b,
923 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
925 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
926 i_rindex, i_gindex, i_bindex, r, g, b, i_alpha, true );
930 p_src_u += i_src_pitch/2;
931 p_src_v += i_src_pitch/2;
936 static void BlendI420YUVPacked( filter_t *p_filter,
937 picture_t *p_dst_pic, const picture_t *p_src,
938 int i_x_offset, int i_y_offset,
939 int i_width, int i_height, int i_alpha )
941 int i_src_pitch, i_dst_pitch;
942 uint8_t *p_dst, *p_src_y;
943 uint8_t *p_src_u, *p_src_v;
944 int i_x, i_y, i_pix_pitch;
945 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
946 int i_l_offset, i_u_offset, i_v_offset;
948 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
949 p_filter->fmt_out.video.i_chroma );
952 i_dst_pitch = p_dst_pic->p->i_pitch;
953 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
954 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
955 p_dst_pic->p->i_pitch *
956 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
958 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
959 0, 0, &p_filter->fmt_in.video, 1 );
960 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
961 0, 0, &p_filter->fmt_in.video, 2 );
962 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
963 0, 0, &p_filter->fmt_in.video, 2 );
965 i_width &= ~1; /* Needs to be a multiple of 2 */
967 /* Draw until we reach the bottom of the subtitle */
968 for( i_y = 0; i_y < i_height; i_y++,
969 p_dst += i_dst_pitch,
970 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
971 p_src_v += i_src_pitch )
973 /* Draw until we reach the end of the line */
974 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
980 vlc_blend_packed( &p_dst[i_x * 2],
981 i_l_offset, i_u_offset, i_v_offset,
982 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2], i_alpha, b_even );
986 p_src_u += i_src_pitch/2;
987 p_src_v += i_src_pitch/2;
992 /***********************************************************************
994 ***********************************************************************/
995 static void BlendPalI420( filter_t *p_filter,
996 picture_t *p_dst, const picture_t *p_src_pic,
997 int i_x_offset, int i_y_offset,
998 int i_width, int i_height, int i_alpha )
1000 int i_src_pitch, i_dst_pitch;
1001 uint8_t *p_src, *p_dst_y;
1004 int i_x, i_y, i_trans;
1005 bool b_even_scanline = i_y_offset % 2;
1007 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1008 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1009 p_filter->fmt_out.video.i_x_offset +
1010 p_dst->p[Y_PLANE].i_pitch *
1011 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1012 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1013 p_filter->fmt_out.video.i_x_offset/2 +
1014 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1015 p_dst->p[U_PLANE].i_pitch;
1016 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1017 p_filter->fmt_out.video.i_x_offset/2 +
1018 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1019 p_dst->p[V_PLANE].i_pitch;
1021 i_src_pitch = p_src_pic->p->i_pitch;
1022 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1023 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1025 #define p_pal p_filter->fmt_in.video.p_palette->palette
1027 /* Draw until we reach the bottom of the subtitle */
1028 for( i_y = 0; i_y < i_height; i_y++,
1029 p_dst_y += i_dst_pitch,
1030 p_src += i_src_pitch,
1031 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1032 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0 )
1034 const uint8_t *p_trans = p_src;
1035 b_even_scanline = !b_even_scanline;
1037 /* Draw until we reach the end of the line */
1038 for( i_x = 0; i_x < i_width; i_x++ )
1040 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1045 p_dst_y[i_x] = vlc_blend( p_pal[p_src[i_x]][0], p_dst_y[i_x], i_trans );
1046 if( b_even_scanline && ((i_x % 2) == 0) )
1048 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src[i_x]][1], p_dst_u[i_x/2], i_trans );
1049 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src[i_x]][2], p_dst_v[i_x/2], i_trans );
1056 static void BlendPalYUVPacked( filter_t *p_filter,
1057 picture_t *p_dst_pic, const picture_t *p_src_pic,
1058 int i_x_offset, int i_y_offset,
1059 int i_width, int i_height, int i_alpha )
1061 int i_src_pitch, i_dst_pitch;
1062 uint8_t *p_src, *p_dst;
1063 int i_x, i_y, i_pix_pitch, i_trans;
1064 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1065 int i_l_offset, i_u_offset, i_v_offset;
1067 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1068 p_filter->fmt_out.video.i_chroma );
1071 i_dst_pitch = p_dst_pic->p->i_pitch;
1072 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1073 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1074 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1076 i_src_pitch = p_src_pic->p->i_pitch;
1077 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1078 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1080 i_width &= ~1; /* Needs to be a multiple of 2 */
1082 #define p_pal p_filter->fmt_in.video.p_palette->palette
1084 /* Draw until we reach the bottom of the subtitle */
1085 for( i_y = 0; i_y < i_height; i_y++,
1086 p_dst += i_dst_pitch, p_src += i_src_pitch )
1088 const uint8_t *p_trans = p_src;
1089 /* Draw until we reach the end of the line */
1090 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1092 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1101 if( p_trans[i_x+1] > 0xaa )
1103 i_u = (p_pal[p_src[i_x]][1] + p_pal[p_src[i_x+1]][1]) >> 1;
1104 i_v = (p_pal[p_src[i_x]][2] + p_pal[p_src[i_x+1]][2]) >> 1;
1108 i_u = p_pal[p_src[i_x]][1];
1109 i_v = p_pal[p_src[i_x]][2];
1112 vlc_blend_packed( &p_dst[i_x * 2],
1113 i_l_offset, i_u_offset, i_v_offset,
1114 p_pal[p_src[i_x]][0], i_u, i_v, i_trans, true );
1118 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 );
1125 static void BlendPalRV( filter_t *p_filter,
1126 picture_t *p_dst_pic, const picture_t *p_src_pic,
1127 int i_x_offset, int i_y_offset,
1128 int i_width, int i_height, int i_alpha )
1130 int i_src_pitch, i_dst_pitch;
1131 uint8_t *p_src, *p_dst;
1132 int i_x, i_y, i_pix_pitch, i_trans;
1133 video_palette_t rgbpalette;
1134 int i_rindex, i_gindex, i_bindex;
1136 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1137 i_dst_pitch = p_dst_pic->p->i_pitch;
1138 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1139 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1140 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1142 i_src_pitch = p_src_pic->p->i_pitch;
1143 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1144 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1146 #define p_pal p_filter->fmt_in.video.p_palette->palette
1147 #define rgbpal rgbpalette.palette
1149 /* Convert palette first */
1150 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && i_y < 256; i_y++ )
1154 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1161 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1163 /* Draw until we reach the bottom of the subtitle */
1164 for( i_y = 0; i_y < i_height; i_y++,
1165 p_dst += i_dst_pitch, p_src += i_src_pitch )
1167 const uint8_t *p_trans = p_src;
1168 /* Draw until we reach the end of the line */
1169 for( i_x = 0; i_x < i_width; i_x++ )
1171 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1176 if( p_filter->fmt_out.video.i_chroma == VLC_CODEC_RGB15 || p_filter->fmt_out.video.i_chroma == VLC_CODEC_RGB16 )
1177 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1178 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1180 &p_filter->fmt_out.video );
1182 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1183 i_rindex, i_gindex, i_bindex,
1184 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1193 /***********************************************************************
1195 ***********************************************************************/
1196 static void BlendRGBAI420( filter_t *p_filter,
1197 picture_t *p_dst, const picture_t *p_src_pic,
1198 int i_x_offset, int i_y_offset,
1199 int i_width, int i_height, int i_alpha )
1201 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1206 int i_x, i_y, i_trans;
1209 bool b_even_scanline = i_y_offset % 2;
1211 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1212 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1213 p_filter->fmt_out.video.i_x_offset +
1214 p_dst->p[Y_PLANE].i_pitch *
1215 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1216 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1217 p_filter->fmt_out.video.i_x_offset/2 +
1218 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1219 p_dst->p[U_PLANE].i_pitch;
1220 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1221 p_filter->fmt_out.video.i_x_offset/2 +
1222 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1223 p_dst->p[V_PLANE].i_pitch;
1225 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1226 i_src_pitch = p_src_pic->p->i_pitch;
1227 p_src = p_src_pic->p->p_pixels +
1228 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1229 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1232 /* Draw until we reach the bottom of the subtitle */
1233 for( i_y = 0; i_y < i_height; i_y++,
1234 p_dst_y += i_dst_pitch,
1235 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1236 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1237 p_src += i_src_pitch )
1239 b_even_scanline = !b_even_scanline;
1241 /* Draw until we reach the end of the line */
1242 for( i_x = 0; i_x < i_width; i_x++ )
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];
1248 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1253 rgb_to_yuv( &y, &u, &v, R, G, B );
1255 p_dst_y[i_x] = vlc_blend( y, p_dst_y[i_x], i_trans );
1256 if( b_even_scanline && i_x % 2 == 0 )
1258 p_dst_u[i_x/2] = vlc_blend( u, p_dst_u[i_x/2], i_trans );
1259 p_dst_v[i_x/2] = vlc_blend( v, p_dst_v[i_x/2], i_trans );
1265 static void BlendRGBAR24( filter_t *p_filter,
1266 picture_t *p_dst_pic, const picture_t *p_src_pic,
1267 int i_x_offset, int i_y_offset,
1268 int i_width, int i_height, int i_alpha )
1270 int i_src_pitch, i_dst_pitch;
1271 uint8_t *p_dst, *p_src;
1272 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1273 int i_rindex, i_gindex, i_bindex;
1275 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1276 i_dst_pitch = p_dst_pic->p->i_pitch;
1277 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1278 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1279 p_dst_pic->p->i_pitch *
1280 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1282 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1283 i_src_pitch = p_src_pic->p->i_pitch;
1284 p_src = p_src_pic->p->p_pixels +
1285 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1286 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1288 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1290 /* Draw until we reach the bottom of the subtitle */
1291 for( i_y = 0; i_y < i_height; i_y++,
1292 p_dst += i_dst_pitch, p_src += i_src_pitch )
1294 /* Draw until we reach the end of the line */
1295 for( i_x = 0; i_x < i_width; i_x++ )
1297 const int R = p_src[i_x * i_src_pix_pitch + 0];
1298 const int G = p_src[i_x * i_src_pix_pitch + 1];
1299 const int B = p_src[i_x * i_src_pix_pitch + 2];
1301 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1306 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1307 i_rindex, i_gindex, i_bindex,
1308 R, G, B, i_trans, true );
1313 static void BlendRGBAR16( filter_t *p_filter,
1314 picture_t *p_dst_pic, const picture_t *p_src_pic,
1315 int i_x_offset, int i_y_offset,
1316 int i_width, int i_height, int i_alpha )
1318 int i_src_pitch, i_dst_pitch;
1319 uint8_t *p_dst, *p_src;
1320 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1322 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1323 i_dst_pitch = p_dst_pic->p->i_pitch;
1324 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1325 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1326 p_dst_pic->p->i_pitch *
1327 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1329 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1330 i_src_pitch = p_src_pic->p->i_pitch;
1331 p_src = p_src_pic->p->p_pixels +
1332 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1333 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1335 /* Draw until we reach the bottom of the subtitle */
1336 for( i_y = 0; i_y < i_height; i_y++,
1337 p_dst += i_dst_pitch, p_src += i_src_pitch )
1339 /* Draw until we reach the end of the line */
1340 for( i_x = 0; i_x < i_width; i_x++ )
1342 const int R = p_src[i_x * i_src_pix_pitch + 0];
1343 const int G = p_src[i_x * i_src_pix_pitch + 1];
1344 const int B = p_src[i_x * i_src_pix_pitch + 2];
1346 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1351 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1352 R, G, B, i_trans, &p_filter->fmt_out.video );
1357 static void BlendRGBAYUVPacked( filter_t *p_filter,
1358 picture_t *p_dst_pic, const picture_t *p_src_pic,
1359 int i_x_offset, int i_y_offset,
1360 int i_width, int i_height, int i_alpha )
1362 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1363 uint8_t *p_dst, *p_src;
1364 int i_x, i_y, i_pix_pitch, i_trans;
1365 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1366 int i_l_offset, i_u_offset, i_v_offset;
1369 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1370 p_filter->fmt_out.video.i_chroma );
1373 i_dst_pitch = p_dst_pic->p->i_pitch;
1374 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1375 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1376 p_dst_pic->p->i_pitch *
1377 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1379 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1380 i_src_pitch = p_src_pic->p->i_pitch;
1381 p_src = p_src_pic->p->p_pixels +
1382 p_filter->fmt_in.video.i_x_offset * i_src_pitch +
1383 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1385 i_width &= ~1; /* Needs to be a multiple of 2 */
1387 /* Draw until we reach the bottom of the subtitle */
1388 for( i_y = 0; i_y < i_height; i_y++,
1389 p_dst += i_dst_pitch,
1390 p_src += i_src_pitch )
1392 /* Draw until we reach the end of the line */
1393 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1395 const int R = p_src[i_x * i_src_pix_pitch + 0];
1396 const int G = p_src[i_x * i_src_pix_pitch + 1];
1397 const int B = p_src[i_x * i_src_pix_pitch + 2];
1399 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1404 rgb_to_yuv( &y, &u, &v, R, G, B );
1406 vlc_blend_packed( &p_dst[i_x * 2],
1407 i_l_offset, i_u_offset, i_v_offset,
1408 y, u, v, i_trans, b_even );