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 #define FCC_YUVA VLC_CODEC_YUVA
50 #define FCC_YUVP VLC_CODEC_YUVP
51 #define FCC_RGBA VLC_CODEC_RGBA
53 #define FCC_I420 VLC_CODEC_I420
54 #define FCC_YV12 VLC_CODEC_YV12
55 #define FCC_YUY2 VLC_CODEC_YUYV
56 #define FCC_UYVY VLC_CODEC_UYVY
57 #define FCC_YVYU VLC_CODEC_YVYU
58 #define FCC_RV15 VLC_CODEC_RGB15
59 #define FCC_RV16 VLC_CODEC_RGB16
60 #define FCC_RV24 VLC_CODEC_RGB24
61 #define FCC_RV32 VLC_CODEC_RGB32
63 /****************************************************************************
65 ****************************************************************************/
66 static void Blend( filter_t *, picture_t *, const picture_t *,
70 static void BlendYUVAI420( filter_t *, picture_t *, const picture_t *,
71 int, int, int, int, int );
72 static void BlendYUVARV16( filter_t *, picture_t *, const picture_t *,
73 int, int, int, int, int );
74 static void BlendYUVARV24( filter_t *, picture_t *, const picture_t *,
75 int, int, int, int, int );
76 static void BlendYUVAYUVPacked( filter_t *, picture_t *, const picture_t *,
77 int, int, int, int, int );
80 static void BlendI420I420( filter_t *, picture_t *, const picture_t *,
81 int, int, int, int, int );
82 static void BlendI420I420_no_alpha(
83 filter_t *, picture_t *, const picture_t *,
85 static void BlendI420R16( filter_t *, picture_t *, const picture_t *,
86 int, int, int, int, int );
87 static void BlendI420R24( filter_t *, picture_t *, const picture_t *,
88 int, int, int, int, int );
89 static void BlendI420YUVPacked( filter_t *, picture_t *,
90 const picture_t *, int, int, int, int, int );
93 static void BlendPalI420( filter_t *, picture_t *, const picture_t *,
94 int, int, int, int, int );
95 static void BlendPalYUVPacked( filter_t *, picture_t *, const picture_t *,
96 int, int, int, int, int );
97 static void BlendPalRV( filter_t *, picture_t *, const picture_t *,
98 int, int, int, int, int );
101 static void BlendRGBAI420( filter_t *, picture_t *, const picture_t *,
102 int, int, int, int, int );
103 static void BlendRGBAYUVPacked( filter_t *, picture_t *,
104 const picture_t *, int, int, int, int, int );
105 static void BlendRGBAR16( filter_t *, picture_t *, const picture_t *,
106 int, int, int, int, int );
107 static void BlendRGBAR24( filter_t *, picture_t *, const picture_t *,
108 int, int, int, int, int );
110 /*****************************************************************************
111 * OpenFilter: probe the filter and return score
112 *****************************************************************************/
113 static int OpenFilter( vlc_object_t *p_this )
115 filter_t *p_filter = (filter_t*)p_this;
117 /* Check if we can handle that format.
118 * We could try to use a chroma filter if we can't. */
119 int in_chroma = p_filter->fmt_in.video.i_chroma;
120 int out_chroma = p_filter->fmt_out.video.i_chroma;
121 if( ( in_chroma != FCC_YUVA && in_chroma != FCC_I420 &&
122 in_chroma != FCC_YV12 && in_chroma != FCC_YUVP &&
123 in_chroma != FCC_RGBA ) ||
124 ( out_chroma != FCC_I420 && out_chroma != FCC_YUY2 &&
125 out_chroma != FCC_YV12 && out_chroma != FCC_UYVY &&
126 out_chroma != FCC_YVYU && out_chroma != FCC_RV15 &&
127 out_chroma != FCC_YVYU && out_chroma != FCC_RV16 &&
128 out_chroma != FCC_RV24 && out_chroma != FCC_RV32 ) )
134 p_filter->pf_video_blend = Blend;
136 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
137 (char *)&p_filter->fmt_in.video.i_chroma,
138 (char *)&p_filter->fmt_out.video.i_chroma );
143 /*****************************************************************************
144 * CloseFilter: clean up the filter
145 *****************************************************************************/
146 static void CloseFilter( vlc_object_t *p_this )
151 /****************************************************************************
152 * Blend: the whole thing
153 ****************************************************************************
154 * This function is called just after the thread is launched.
155 ****************************************************************************/
156 typedef void (*BlendFunction)( filter_t *,
157 picture_t *, const picture_t *,
158 int , int , int , int , int );
160 #define FCC_PLANAR_420 { FCC_I420, FCC_YV12, 0 }
161 #define FCC_PACKED_422 { FCC_YUY2, FCC_UYVY, FCC_YVYU, 0 }
162 #define FCC_RGB_16 { FCC_RV15, FCC_RV16, 0 }
163 #define FCC_RGB_24 { FCC_RV24, FCC_RV32, 0 }
165 #define BLEND_CFG( fccSrc, fctPlanar, fctPacked, fctRgb16, fctRgb24 ) \
166 { .src = fccSrc, .p_dst = FCC_PLANAR_420, .pf_blend = fctPlanar }, \
167 { .src = fccSrc, .p_dst = FCC_PACKED_422, .pf_blend = fctPacked }, \
168 { .src = fccSrc, .p_dst = FCC_RGB_16, .pf_blend = fctRgb16 }, \
169 { .src = fccSrc, .p_dst = FCC_RGB_24, .pf_blend = fctRgb24 }
174 vlc_fourcc_t p_dst[16];
175 BlendFunction pf_blend;
178 BLEND_CFG( FCC_YUVA, BlendYUVAI420, BlendYUVAYUVPacked, BlendYUVARV16, BlendYUVARV24 ),
180 BLEND_CFG( FCC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ),
182 BLEND_CFG( FCC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ),
184 BLEND_CFG( FCC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
186 BLEND_CFG( FCC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
191 static void Blend( filter_t *p_filter,
192 picture_t *p_dst, const picture_t *p_src,
193 int i_x_offset, int i_y_offset, int i_alpha )
195 int i_width, i_height;
200 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
201 (int)p_filter->fmt_in.video.i_visible_width);
203 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
204 (int)p_filter->fmt_in.video.i_visible_height);
206 if( i_width <= 0 || i_height <= 0 )
209 video_format_FixRgb( &p_filter->fmt_out.video );
210 video_format_FixRgb( &p_filter->fmt_in.video );
213 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
214 (char *)&p_filter->fmt_in.video.i_chroma,
215 (char *)&p_filter->fmt_out.video.i_chroma );
218 for( int i = 0; p_blend_cfg[i].src != 0; i++ )
220 if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma )
222 for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ )
224 if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma )
227 p_blend_cfg[i].pf_blend( p_filter, p_dst, p_src,
228 i_x_offset, i_y_offset,
229 i_width, i_height, i_alpha );
234 msg_Dbg( p_filter, "no matching alpha blending routine "
235 "(chroma: %4.4s -> %4.4s)",
236 (char *)&p_filter->fmt_in.video.i_chroma,
237 (char *)&p_filter->fmt_out.video.i_chroma );
240 /***********************************************************************
242 ***********************************************************************/
243 static inline uint8_t vlc_uint8( int v )
252 #define MAX_TRANS 255
255 static inline int vlc_blend( int v1, int v2, int a )
257 /* TODO bench if the tests really increase speed */
260 else if( a == MAX_TRANS )
262 return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
265 static inline int vlc_alpha( int t, int a )
269 return (t * a) / 255;
272 static inline void yuv_to_rgb( int *r, int *g, int *b,
273 uint8_t y1, uint8_t u1, uint8_t v1 )
275 /* macros used for YUV pixel conversions */
276 # define SCALEBITS 10
277 # define ONE_HALF (1 << (SCALEBITS - 1))
278 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
280 int y, cb, cr, r_add, g_add, b_add;
284 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
285 g_add = - FIX(0.34414*255.0/224.0) * cb
286 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
287 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
288 y = (y1 - 16) * FIX(255.0/219.0);
289 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
290 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
291 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
297 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
298 int r, int g, int b )
300 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
301 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
302 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
305 static uint8_t *vlc_plane_start( int *pi_pitch,
306 const picture_t *p_picture,
308 int i_x_offset, int i_y_offset,
309 const video_format_t *p_fmt,
312 const int i_pitch = p_picture->p[i_plane].i_pitch;
313 uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
315 const int i_dx = ( i_x_offset + p_fmt->i_x_offset ) / r;
316 const int i_dy = ( i_y_offset + p_fmt->i_y_offset ) / r;
320 return &p_pixels[ i_dy * i_pitch + i_dx ];
323 static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma )
325 static const struct {
329 { FCC_YUY2, 0, 1, 3 },
330 { FCC_UYVY, 1, 0, 2 },
331 { FCC_YVYU, 0, 3, 1 },
336 for( i = 0; p_index[i].chroma != 0; i++ )
338 if( p_index[i].chroma == i_chroma )
341 *pi_y = p_index[i].y;
342 *pi_u = p_index[i].u;
343 *pi_v = p_index[i].v;
346 static void vlc_blend_packed( uint8_t *p_dst,
347 int i_offset0, int i_offset1, int i_offset2,
348 int c0, int c1, int c2, int i_alpha,
351 p_dst[i_offset0] = vlc_blend( c0, p_dst[i_offset0], i_alpha );
354 p_dst[i_offset1] = vlc_blend( c1, p_dst[i_offset1], i_alpha );
355 p_dst[i_offset2] = vlc_blend( c2, p_dst[i_offset2], i_alpha );
359 static void vlc_blend_rgb16( uint16_t *p_dst,
360 int R, int G, int B, int i_alpha,
361 const video_format_t *p_fmt )
363 const int i_pix = *p_dst;
364 const int r = ( i_pix & p_fmt->i_rmask ) >> p_fmt->i_lrshift;
365 const int g = ( i_pix & p_fmt->i_gmask ) >> p_fmt->i_lgshift;
366 const int b = ( i_pix & p_fmt->i_bmask ) >> p_fmt->i_lbshift;
368 *p_dst = ( vlc_blend( R >> p_fmt->i_rrshift, r, i_alpha ) << p_fmt->i_lrshift ) |
369 ( vlc_blend( G >> p_fmt->i_rgshift, g, i_alpha ) << p_fmt->i_lgshift ) |
370 ( vlc_blend( B >> p_fmt->i_rbshift, b, i_alpha ) << p_fmt->i_lbshift );
373 static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex,
374 const video_format_t *p_fmt )
376 if( p_fmt->i_chroma != FCC_RV24 && p_fmt->i_chroma != FCC_RV32 )
379 /* XXX it will works only if mask are 8 bits aligned */
380 #ifdef WORDS_BIGENDIAN
381 const int i_mask_bits = p_fmt->i_chroma == FCC_RV24 ? 24 : 32;
382 *pi_rindex = ( i_mask_bits - p_fmt->i_lrshift ) / 8;
383 *pi_gindex = ( i_mask_bits - p_fmt->i_lgshift ) / 8;
384 *pi_bindex = ( i_mask_bits - p_fmt->i_lbshift ) / 8;
386 *pi_rindex = p_fmt->i_lrshift / 8;
387 *pi_gindex = p_fmt->i_lgshift / 8;
388 *pi_bindex = p_fmt->i_lbshift / 8;
392 /***********************************************************************
394 ***********************************************************************/
395 static void BlendYUVAI420( filter_t *p_filter,
396 picture_t *p_dst, const picture_t *p_src,
397 int i_x_offset, int i_y_offset,
398 int i_width, int i_height, int i_alpha )
400 int i_src_pitch, i_dst_pitch;
401 uint8_t *p_src_y, *p_dst_y;
402 uint8_t *p_src_u, *p_dst_u;
403 uint8_t *p_src_v, *p_dst_v;
405 int i_x, i_y, i_trans = 0;
406 bool b_even_scanline = i_y_offset % 2;
408 p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
409 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
410 p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
411 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
412 p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
413 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
415 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
416 0, 0, &p_filter->fmt_in.video, 1 );
417 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
418 0, 0, &p_filter->fmt_in.video, 2 );
419 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
420 0, 0, &p_filter->fmt_in.video, 2 );
421 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
422 0, 0, &p_filter->fmt_in.video, 1 );
424 /* Draw until we reach the bottom of the subtitle */
425 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
426 p_dst_y += i_dst_pitch, p_src_y += i_src_pitch,
427 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
428 p_src_u += i_src_pitch,
429 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
430 p_src_v += i_src_pitch )
432 b_even_scanline = !b_even_scanline;
434 /* Draw until we reach the end of the line */
435 for( i_x = 0; i_x < i_width; i_x++ )
438 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
444 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_trans );
445 if( b_even_scanline && i_x % 2 == 0 )
447 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x], p_dst_u[i_x/2], i_trans );
448 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x], p_dst_v[i_x/2], i_trans );
454 static void BlendYUVARV16( filter_t *p_filter,
455 picture_t *p_dst_pic, const picture_t *p_src,
456 int i_x_offset, int i_y_offset,
457 int i_width, int i_height, int i_alpha )
459 int i_src_pitch, i_dst_pitch;
460 uint8_t *p_dst, *p_src_y;
461 uint8_t *p_src_u, *p_src_v;
463 int i_x, i_y, i_pix_pitch, i_trans = 0;
466 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
467 i_dst_pitch = p_dst_pic->p->i_pitch;
468 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
469 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
470 p_dst_pic->p->i_pitch *
471 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
473 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
474 0, 0, &p_filter->fmt_in.video, 1 );
475 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
476 0, 0, &p_filter->fmt_in.video, 2 );
477 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
478 0, 0, &p_filter->fmt_in.video, 2 );
479 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
480 0, 0, &p_filter->fmt_in.video, 1 );
482 /* Draw until we reach the bottom of the subtitle */
483 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
484 p_dst += i_dst_pitch,
485 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
486 p_src_v += i_src_pitch )
488 /* Draw until we reach the end of the line */
489 for( i_x = 0; i_x < i_width; i_x++ )
492 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
497 yuv_to_rgb( &r, &g, &b,
498 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
500 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
501 r, g, b, i_trans, &p_filter->fmt_out.video );
506 static void BlendYUVARV24( filter_t *p_filter,
507 picture_t *p_dst_pic, const picture_t *p_src,
508 int i_x_offset, int i_y_offset,
509 int i_width, int i_height, int i_alpha )
511 int i_src_pitch, i_dst_pitch;
512 uint8_t *p_dst, *p_src_y;
513 uint8_t *p_src_u, *p_src_v;
515 int i_x, i_y, i_pix_pitch, i_trans = 0;
518 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
519 i_dst_pitch = p_dst_pic->p->i_pitch;
520 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
521 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
522 p_dst_pic->p->i_pitch *
523 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
525 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
526 0, 0, &p_filter->fmt_in.video, 1 );
527 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
528 0, 0, &p_filter->fmt_in.video, 2 );
529 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
530 0, 0, &p_filter->fmt_in.video, 2 );
531 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
532 0, 0, &p_filter->fmt_in.video, 1 );
534 if( (i_pix_pitch == 4)
535 && (((((intptr_t)p_dst)|i_dst_pitch) /* FIXME? */
539 ** if picture pixels are 32 bits long and lines addresses are 32 bit
540 ** aligned, optimize rendering
542 uint32_t *p32_dst = (uint32_t *)p_dst;
543 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
545 int i_rshift, i_gshift, i_bshift;
546 uint32_t i_rmask, i_gmask, i_bmask;
548 i_rmask = p_filter->fmt_out.video.i_rmask;
549 i_gmask = p_filter->fmt_out.video.i_gmask;
550 i_bmask = p_filter->fmt_out.video.i_bmask;
551 i_rshift = p_filter->fmt_out.video.i_lrshift;
552 i_gshift = p_filter->fmt_out.video.i_lgshift;
553 i_bshift = p_filter->fmt_out.video.i_lbshift;
555 /* Draw until we reach the bottom of the subtitle */
556 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
557 p32_dst += i32_dst_pitch,
558 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
559 p_src_v += i_src_pitch )
561 /* Draw until we reach the end of the line */
562 for( i_x = 0; i_x < i_width; i_x++ )
565 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
569 if( i_trans == MAX_TRANS )
571 /* Completely opaque. Completely overwrite underlying pixel */
572 yuv_to_rgb( &r, &g, &b,
573 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
575 p32_dst[i_x] = (r<<i_rshift) |
582 uint32_t i_pix_dst = p32_dst[i_x];
583 yuv_to_rgb( &r, &g, &b,
584 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
586 p32_dst[i_x] = ( vlc_blend( r, (i_pix_dst & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
587 ( vlc_blend( g, (i_pix_dst & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
588 ( vlc_blend( b, (i_pix_dst & i_bmask)>>i_bshift, i_trans ) << i_bshift );
595 int i_rindex, i_gindex, i_bindex;
596 uint32_t i_rmask, i_gmask, i_bmask;
598 i_rmask = p_filter->fmt_out.video.i_rmask;
599 i_gmask = p_filter->fmt_out.video.i_gmask;
600 i_bmask = p_filter->fmt_out.video.i_bmask;
602 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
604 /* Draw until we reach the bottom of the subtitle */
605 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
606 p_dst += i_dst_pitch,
607 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
608 p_src_v += i_src_pitch )
610 /* Draw until we reach the end of the line */
611 for( i_x = 0; i_x < i_width; i_x++ )
614 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
619 yuv_to_rgb( &r, &g, &b,
620 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
622 vlc_blend_packed( &p_dst[ i_x * i_pix_pitch],
623 i_rindex, i_gindex, i_bindex,
624 r, g, b, i_alpha, true );
630 static void BlendYUVAYUVPacked( filter_t *p_filter,
631 picture_t *p_dst_pic, const picture_t *p_src,
632 int i_x_offset, int i_y_offset,
633 int i_width, int i_height, int i_alpha )
635 int i_src_pitch, i_dst_pitch;
636 uint8_t *p_dst, *p_src_y;
637 uint8_t *p_src_u, *p_src_v;
639 int i_x, i_y, i_pix_pitch, i_trans = 0;
640 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
641 int i_l_offset, i_u_offset, i_v_offset;
643 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
644 p_filter->fmt_out.video.i_chroma );
647 i_dst_pitch = p_dst_pic->p->i_pitch;
648 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
649 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
650 p_dst_pic->p->i_pitch *
651 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
653 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
654 0, 0, &p_filter->fmt_in.video, 1 );
655 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
656 0, 0, &p_filter->fmt_in.video, 2 );
657 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
658 0, 0, &p_filter->fmt_in.video, 2 );
659 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
660 0, 0, &p_filter->fmt_in.video, 1 );
662 i_width &= ~1; /* Needs to be a multiple of 2 */
664 /* Draw until we reach the bottom of the subtitle */
665 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
666 p_dst += i_dst_pitch,
667 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
668 p_src_v += i_src_pitch )
670 /* Draw until we reach the end of the line */
671 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
673 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
682 /* FIXME what's with 0xaa ? */
683 if( p_trans[i_x+1] > 0xaa )
685 i_u = (p_src_u[i_x]+p_src_u[i_x+1])>>1;
686 i_v = (p_src_v[i_x]+p_src_v[i_x+1])>>1;
694 vlc_blend_packed( &p_dst[i_x * 2],
695 i_l_offset, i_u_offset, i_v_offset,
696 p_src_y[i_x], i_u, i_v, i_trans, true );
700 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 );
705 /***********************************************************************
707 ***********************************************************************/
708 static void BlendI420I420( filter_t *p_filter,
709 picture_t *p_dst, const picture_t *p_src,
710 int i_x_offset, int i_y_offset,
711 int i_width, int i_height, int i_alpha )
713 int i_src_pitch, i_dst_pitch;
714 uint8_t *p_src_y, *p_dst_y;
715 uint8_t *p_src_u, *p_dst_u;
716 uint8_t *p_src_v, *p_dst_v;
718 bool b_even_scanline = i_y_offset % 2;
720 if( i_alpha == 0xff )
722 BlendI420I420_no_alpha( p_filter, p_dst, p_src,
723 i_x_offset, i_y_offset, i_width, i_height );
728 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
729 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
730 p_filter->fmt_out.video.i_x_offset +
731 p_dst->p[Y_PLANE].i_pitch *
732 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
733 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
734 p_filter->fmt_out.video.i_x_offset/2 +
735 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
736 p_dst->p[U_PLANE].i_pitch;
737 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
738 p_filter->fmt_out.video.i_x_offset/2 +
739 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
740 p_dst->p[V_PLANE].i_pitch;
742 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
743 0, 0, &p_filter->fmt_in.video, 1 );
744 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
745 0, 0, &p_filter->fmt_in.video, 2 );
746 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
747 0, 0, &p_filter->fmt_in.video, 2 );
750 /* Draw until we reach the bottom of the subtitle */
751 for( i_y = 0; i_y < i_height; i_y++,
752 p_dst_y += i_dst_pitch,
753 p_src_y += i_src_pitch )
755 if( b_even_scanline )
757 p_dst_u += i_dst_pitch/2;
758 p_dst_v += i_dst_pitch/2;
760 b_even_scanline = !b_even_scanline;
762 /* Draw until we reach the end of the line */
763 for( i_x = 0; i_x < i_width; i_x++ )
769 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_alpha );
770 if( b_even_scanline && i_x % 2 == 0 )
772 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x/2], p_dst_u[i_x/2], i_alpha );
773 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x/2], p_dst_v[i_x/2], i_alpha );
778 p_src_u += i_src_pitch/2;
779 p_src_v += i_src_pitch/2;
783 static void BlendI420I420_no_alpha( filter_t *p_filter,
784 picture_t *p_dst, const picture_t *p_src,
785 int i_x_offset, int i_y_offset,
786 int i_width, int i_height )
788 int i_src_pitch, i_dst_pitch;
789 uint8_t *p_src_y, *p_dst_y;
790 uint8_t *p_src_u, *p_dst_u;
791 uint8_t *p_src_v, *p_dst_v;
793 bool b_even_scanline = i_y_offset % 2;
795 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
796 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
797 p_filter->fmt_out.video.i_x_offset +
798 p_dst->p[Y_PLANE].i_pitch *
799 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
800 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
801 p_filter->fmt_out.video.i_x_offset/2 +
802 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
803 p_dst->p[U_PLANE].i_pitch;
804 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
805 p_filter->fmt_out.video.i_x_offset/2 +
806 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
807 p_dst->p[V_PLANE].i_pitch;
809 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
810 0, 0, &p_filter->fmt_in.video, 1 );
811 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
812 0, 0, &p_filter->fmt_in.video, 2 );
813 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
814 0, 0, &p_filter->fmt_in.video, 2 );
818 /* Draw until we reach the bottom of the subtitle */
819 for( i_y = 0; i_y < i_height;
820 i_y++, p_dst_y += i_dst_pitch, p_src_y += i_src_pitch )
822 /* Completely opaque. Completely overwrite underlying pixel */
823 vlc_memcpy( p_dst_y, p_src_y, i_width );
824 if( b_even_scanline )
826 p_dst_u += i_dst_pitch/2;
827 p_dst_v += i_dst_pitch/2;
831 vlc_memcpy( p_dst_u, p_src_u, i_width/2 );
832 vlc_memcpy( p_dst_v, p_src_v, i_width/2 );
834 b_even_scanline = !b_even_scanline;
837 p_src_u += i_src_pitch/2;
838 p_src_v += i_src_pitch/2;
843 static void BlendI420R16( filter_t *p_filter,
844 picture_t *p_dst_pic, const picture_t *p_src,
845 int i_x_offset, int i_y_offset,
846 int i_width, int i_height, int i_alpha )
848 int i_src_pitch, i_dst_pitch;
849 uint8_t *p_dst, *p_src_y;
850 uint8_t *p_src_u, *p_src_v;
851 int i_x, i_y, i_pix_pitch;
854 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
855 i_dst_pitch = p_dst_pic->p->i_pitch;
856 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
857 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
858 p_dst_pic->p->i_pitch *
859 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
861 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
862 0, 0, &p_filter->fmt_in.video, 1 );
863 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
864 0, 0, &p_filter->fmt_in.video, 2 );
865 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
866 0, 0, &p_filter->fmt_in.video, 2 );
868 /* Draw until we reach the bottom of the subtitle */
869 for( i_y = 0; i_y < i_height; i_y++,
870 p_dst += i_dst_pitch,
871 p_src_y += i_src_pitch )
873 /* Draw until we reach the end of the line */
874 for( i_x = 0; i_x < i_width; i_x++ )
877 yuv_to_rgb( &r, &g, &b,
878 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
880 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
881 r, g, b, i_alpha, &p_filter->fmt_out.video );
885 p_src_u += i_src_pitch/2;
886 p_src_v += i_src_pitch/2;
891 static void BlendI420R24( filter_t *p_filter,
892 picture_t *p_dst_pic, const picture_t *p_src,
893 int i_x_offset, int i_y_offset,
894 int i_width, int i_height, int i_alpha )
896 int i_src_pitch, i_dst_pitch;
897 uint8_t *p_dst, *p_src_y;
898 uint8_t *p_src_u, *p_src_v;
899 int i_x, i_y, i_pix_pitch;
900 int i_rindex, i_gindex, i_bindex;
903 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
904 i_dst_pitch = p_dst_pic->p->i_pitch;
905 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
906 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
907 p_dst_pic->p->i_pitch *
908 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
910 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
911 0, 0, &p_filter->fmt_in.video, 1 );
912 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
913 0, 0, &p_filter->fmt_in.video, 2 );
914 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
915 0, 0, &p_filter->fmt_in.video, 2 );
917 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
919 /* Draw until we reach the bottom of the subtitle */
920 for( i_y = 0; i_y < i_height; i_y++,
921 p_dst += i_dst_pitch,
922 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
923 p_src_v += i_src_pitch )
925 /* Draw until we reach the end of the line */
926 for( i_x = 0; i_x < i_width; i_x++ )
932 yuv_to_rgb( &r, &g, &b,
933 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
935 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
936 i_rindex, i_gindex, i_bindex, r, g, b, i_alpha, true );
940 p_src_u += i_src_pitch/2;
941 p_src_v += i_src_pitch/2;
946 static void BlendI420YUVPacked( filter_t *p_filter,
947 picture_t *p_dst_pic, const picture_t *p_src,
948 int i_x_offset, int i_y_offset,
949 int i_width, int i_height, int i_alpha )
951 int i_src_pitch, i_dst_pitch;
952 uint8_t *p_dst, *p_src_y;
953 uint8_t *p_src_u, *p_src_v;
954 int i_x, i_y, i_pix_pitch;
955 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
956 int i_l_offset, i_u_offset, i_v_offset;
958 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
959 p_filter->fmt_out.video.i_chroma );
962 i_dst_pitch = p_dst_pic->p->i_pitch;
963 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
964 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
965 p_dst_pic->p->i_pitch *
966 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
968 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
969 0, 0, &p_filter->fmt_in.video, 1 );
970 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
971 0, 0, &p_filter->fmt_in.video, 2 );
972 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
973 0, 0, &p_filter->fmt_in.video, 2 );
975 i_width &= ~1; /* Needs to be a multiple of 2 */
977 /* Draw until we reach the bottom of the subtitle */
978 for( i_y = 0; i_y < i_height; i_y++,
979 p_dst += i_dst_pitch,
980 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
981 p_src_v += i_src_pitch )
983 /* Draw until we reach the end of the line */
984 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
990 vlc_blend_packed( &p_dst[i_x * 2],
991 i_l_offset, i_u_offset, i_v_offset,
992 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2], i_alpha, b_even );
996 p_src_u += i_src_pitch/2;
997 p_src_v += i_src_pitch/2;
1002 /***********************************************************************
1004 ***********************************************************************/
1005 static void BlendPalI420( filter_t *p_filter,
1006 picture_t *p_dst, const picture_t *p_src_pic,
1007 int i_x_offset, int i_y_offset,
1008 int i_width, int i_height, int i_alpha )
1010 int i_src_pitch, i_dst_pitch;
1011 uint8_t *p_src, *p_dst_y;
1014 int i_x, i_y, i_trans;
1015 bool b_even_scanline = i_y_offset % 2;
1017 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1018 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1019 p_filter->fmt_out.video.i_x_offset +
1020 p_dst->p[Y_PLANE].i_pitch *
1021 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1022 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1023 p_filter->fmt_out.video.i_x_offset/2 +
1024 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1025 p_dst->p[U_PLANE].i_pitch;
1026 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1027 p_filter->fmt_out.video.i_x_offset/2 +
1028 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1029 p_dst->p[V_PLANE].i_pitch;
1031 i_src_pitch = p_src_pic->p->i_pitch;
1032 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1033 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1035 #define p_pal p_filter->fmt_in.video.p_palette->palette
1037 /* Draw until we reach the bottom of the subtitle */
1038 for( i_y = 0; i_y < i_height; i_y++,
1039 p_dst_y += i_dst_pitch,
1040 p_src += i_src_pitch,
1041 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1042 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0 )
1044 const uint8_t *p_trans = p_src;
1045 b_even_scanline = !b_even_scanline;
1047 /* Draw until we reach the end of the line */
1048 for( i_x = 0; i_x < i_width; i_x++ )
1050 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1055 p_dst_y[i_x] = vlc_blend( p_pal[p_src[i_x]][0], p_dst_y[i_x], i_trans );
1056 if( b_even_scanline && ((i_x % 2) == 0) )
1058 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src[i_x]][1], p_dst_u[i_x/2], i_trans );
1059 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src[i_x]][2], p_dst_v[i_x/2], i_trans );
1066 static void BlendPalYUVPacked( filter_t *p_filter,
1067 picture_t *p_dst_pic, const picture_t *p_src_pic,
1068 int i_x_offset, int i_y_offset,
1069 int i_width, int i_height, int i_alpha )
1071 int i_src_pitch, i_dst_pitch;
1072 uint8_t *p_src, *p_dst;
1073 int i_x, i_y, i_pix_pitch, i_trans;
1074 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1075 int i_l_offset, i_u_offset, i_v_offset;
1077 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1078 p_filter->fmt_out.video.i_chroma );
1081 i_dst_pitch = p_dst_pic->p->i_pitch;
1082 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1083 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1084 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1086 i_src_pitch = p_src_pic->p->i_pitch;
1087 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1088 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1090 i_width &= ~1; /* Needs to be a multiple of 2 */
1092 #define p_pal p_filter->fmt_in.video.p_palette->palette
1094 /* Draw until we reach the bottom of the subtitle */
1095 for( i_y = 0; i_y < i_height; i_y++,
1096 p_dst += i_dst_pitch, p_src += i_src_pitch )
1098 const uint8_t *p_trans = p_src;
1099 /* Draw until we reach the end of the line */
1100 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1102 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1111 if( p_trans[i_x+1] > 0xaa )
1113 i_u = (p_pal[p_src[i_x]][1] + p_pal[p_src[i_x+1]][1]) >> 1;
1114 i_v = (p_pal[p_src[i_x]][2] + p_pal[p_src[i_x+1]][2]) >> 1;
1118 i_u = p_pal[p_src[i_x]][1];
1119 i_v = p_pal[p_src[i_x]][2];
1122 vlc_blend_packed( &p_dst[i_x * 2],
1123 i_l_offset, i_u_offset, i_v_offset,
1124 p_pal[p_src[i_x]][0], i_u, i_v, i_trans, true );
1128 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 );
1135 static void BlendPalRV( filter_t *p_filter,
1136 picture_t *p_dst_pic, const picture_t *p_src_pic,
1137 int i_x_offset, int i_y_offset,
1138 int i_width, int i_height, int i_alpha )
1140 int i_src_pitch, i_dst_pitch;
1141 uint8_t *p_src, *p_dst;
1142 int i_x, i_y, i_pix_pitch, i_trans;
1143 video_palette_t rgbpalette;
1144 int i_rindex, i_gindex, i_bindex;
1146 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1147 i_dst_pitch = p_dst_pic->p->i_pitch;
1148 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1149 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1150 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1152 i_src_pitch = p_src_pic->p->i_pitch;
1153 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1154 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1156 #define p_pal p_filter->fmt_in.video.p_palette->palette
1157 #define rgbpal rgbpalette.palette
1159 /* Convert palette first */
1160 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && i_y < 256; i_y++ )
1164 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1171 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1173 /* Draw until we reach the bottom of the subtitle */
1174 for( i_y = 0; i_y < i_height; i_y++,
1175 p_dst += i_dst_pitch, p_src += i_src_pitch )
1177 const uint8_t *p_trans = p_src;
1178 /* Draw until we reach the end of the line */
1179 for( i_x = 0; i_x < i_width; i_x++ )
1181 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1186 if( p_filter->fmt_out.video.i_chroma == FCC_RV15 || p_filter->fmt_out.video.i_chroma == FCC_RV16 )
1187 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1188 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1190 &p_filter->fmt_out.video );
1192 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1193 i_rindex, i_gindex, i_bindex,
1194 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1203 /***********************************************************************
1205 ***********************************************************************/
1206 static void BlendRGBAI420( filter_t *p_filter,
1207 picture_t *p_dst, const picture_t *p_src_pic,
1208 int i_x_offset, int i_y_offset,
1209 int i_width, int i_height, int i_alpha )
1211 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1216 int i_x, i_y, i_trans;
1219 bool b_even_scanline = i_y_offset % 2;
1221 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1222 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1223 p_filter->fmt_out.video.i_x_offset +
1224 p_dst->p[Y_PLANE].i_pitch *
1225 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1226 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1227 p_filter->fmt_out.video.i_x_offset/2 +
1228 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1229 p_dst->p[U_PLANE].i_pitch;
1230 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1231 p_filter->fmt_out.video.i_x_offset/2 +
1232 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1233 p_dst->p[V_PLANE].i_pitch;
1235 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1236 i_src_pitch = p_src_pic->p->i_pitch;
1237 p_src = p_src_pic->p->p_pixels +
1238 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1239 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1242 /* Draw until we reach the bottom of the subtitle */
1243 for( i_y = 0; i_y < i_height; i_y++,
1244 p_dst_y += i_dst_pitch,
1245 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1246 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1247 p_src += i_src_pitch )
1249 b_even_scanline = !b_even_scanline;
1251 /* Draw until we reach the end of the line */
1252 for( i_x = 0; i_x < i_width; i_x++ )
1254 const int R = p_src[i_x * i_src_pix_pitch + 0];
1255 const int G = p_src[i_x * i_src_pix_pitch + 1];
1256 const int B = p_src[i_x * i_src_pix_pitch + 2];
1258 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1263 rgb_to_yuv( &y, &u, &v, R, G, B );
1265 p_dst_y[i_x] = vlc_blend( y, p_dst_y[i_x], i_trans );
1266 if( b_even_scanline && i_x % 2 == 0 )
1268 p_dst_u[i_x/2] = vlc_blend( u, p_dst_u[i_x/2], i_trans );
1269 p_dst_v[i_x/2] = vlc_blend( v, p_dst_v[i_x/2], i_trans );
1275 static void BlendRGBAR24( filter_t *p_filter,
1276 picture_t *p_dst_pic, const picture_t *p_src_pic,
1277 int i_x_offset, int i_y_offset,
1278 int i_width, int i_height, int i_alpha )
1280 int i_src_pitch, i_dst_pitch;
1281 uint8_t *p_dst, *p_src;
1282 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1283 int i_rindex, i_gindex, i_bindex;
1285 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1286 i_dst_pitch = p_dst_pic->p->i_pitch;
1287 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1288 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1289 p_dst_pic->p->i_pitch *
1290 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1292 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1293 i_src_pitch = p_src_pic->p->i_pitch;
1294 p_src = p_src_pic->p->p_pixels +
1295 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1296 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1298 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1300 /* Draw until we reach the bottom of the subtitle */
1301 for( i_y = 0; i_y < i_height; i_y++,
1302 p_dst += i_dst_pitch, p_src += i_src_pitch )
1304 /* Draw until we reach the end of the line */
1305 for( i_x = 0; i_x < i_width; i_x++ )
1307 const int R = p_src[i_x * i_src_pix_pitch + 0];
1308 const int G = p_src[i_x * i_src_pix_pitch + 1];
1309 const int B = p_src[i_x * i_src_pix_pitch + 2];
1311 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1316 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1317 i_rindex, i_gindex, i_bindex,
1318 R, G, B, i_trans, true );
1323 static void BlendRGBAR16( filter_t *p_filter,
1324 picture_t *p_dst_pic, const picture_t *p_src_pic,
1325 int i_x_offset, int i_y_offset,
1326 int i_width, int i_height, int i_alpha )
1328 int i_src_pitch, i_dst_pitch;
1329 uint8_t *p_dst, *p_src;
1330 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1332 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1333 i_dst_pitch = p_dst_pic->p->i_pitch;
1334 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1335 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1336 p_dst_pic->p->i_pitch *
1337 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1339 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1340 i_src_pitch = p_src_pic->p->i_pitch;
1341 p_src = p_src_pic->p->p_pixels +
1342 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1343 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1345 /* Draw until we reach the bottom of the subtitle */
1346 for( i_y = 0; i_y < i_height; i_y++,
1347 p_dst += i_dst_pitch, p_src += i_src_pitch )
1349 /* Draw until we reach the end of the line */
1350 for( i_x = 0; i_x < i_width; i_x++ )
1352 const int R = p_src[i_x * i_src_pix_pitch + 0];
1353 const int G = p_src[i_x * i_src_pix_pitch + 1];
1354 const int B = p_src[i_x * i_src_pix_pitch + 2];
1356 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1361 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1362 R, G, B, i_trans, &p_filter->fmt_out.video );
1367 static void BlendRGBAYUVPacked( filter_t *p_filter,
1368 picture_t *p_dst_pic, const picture_t *p_src_pic,
1369 int i_x_offset, int i_y_offset,
1370 int i_width, int i_height, int i_alpha )
1372 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1373 uint8_t *p_dst, *p_src;
1374 int i_x, i_y, i_pix_pitch, i_trans;
1375 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1376 int i_l_offset, i_u_offset, i_v_offset;
1379 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1380 p_filter->fmt_out.video.i_chroma );
1383 i_dst_pitch = p_dst_pic->p->i_pitch;
1384 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1385 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1386 p_dst_pic->p->i_pitch *
1387 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1389 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1390 i_src_pitch = p_src_pic->p->i_pitch;
1391 p_src = p_src_pic->p->p_pixels +
1392 p_filter->fmt_in.video.i_x_offset * i_src_pitch +
1393 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1395 i_width &= ~1; /* Needs to be a multiple of 2 */
1397 /* Draw until we reach the bottom of the subtitle */
1398 for( i_y = 0; i_y < i_height; i_y++,
1399 p_dst += i_dst_pitch,
1400 p_src += i_src_pitch )
1402 /* Draw until we reach the end of the line */
1403 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1405 const int R = p_src[i_x * i_src_pix_pitch + 0];
1406 const int G = p_src[i_x * i_src_pix_pitch + 1];
1407 const int B = p_src[i_x * i_src_pix_pitch + 2];
1409 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1414 rgb_to_yuv( &y, &u, &v, R, G, B );
1416 vlc_blend_packed( &p_dst[i_x * 2],
1417 i_l_offset, i_u_offset, i_v_offset,
1418 y, u, v, i_trans, b_even );