1 /*****************************************************************************
2 * blend.c: alpha blend 2 pictures together
3 *****************************************************************************
4 * Copyright (C) 2003-2007 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 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include "vlc_filter.h"
37 /*****************************************************************************
38 * filter_sys_t : filter descriptor
39 *****************************************************************************/
45 /****************************************************************************
47 ****************************************************************************/
48 static int OpenFilter ( vlc_object_t * );
49 static void CloseFilter( vlc_object_t * );
51 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
54 /* TODO i_alpha support for BlendR16 */
56 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
57 int, int, int, int, int );
58 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
59 int, int, int, int, int );
60 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
61 int, int, int, int, int );
62 static void BlendYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
63 int, int, int, int, int );
66 static void BlendI420I420( filter_t *, picture_t *, picture_t *, picture_t *,
67 int, int, int, int, int );
68 static void BlendI420I420_no_alpha(
69 filter_t *, picture_t *, picture_t *, picture_t *,
71 static void BlendI420R16( filter_t *, picture_t *, picture_t *, picture_t *,
72 int, int, int, int, int );
73 static void BlendI420R24( filter_t *, picture_t *, picture_t *, picture_t *,
74 int, int, int, int, int );
75 static void BlendI420YUVPacked( filter_t *, picture_t *, picture_t *,
76 picture_t *, int, int, int, int, int );
79 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
80 int, int, int, int, int );
81 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
82 int, int, int, int, int );
83 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
84 int, int, int, int, int );
87 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
88 int, int, int, int, int );
89 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
90 picture_t *, int, int, int, int, int );
91 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
92 int, int, int, int, int );
93 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
94 int, int, int, int, int );
96 /*****************************************************************************
98 *****************************************************************************/
100 set_description( N_("Video pictures blending") );
101 set_capability( "video blending", 100 );
102 set_callbacks( OpenFilter, CloseFilter );
105 /*****************************************************************************
106 * OpenFilter: probe the filter and return score
107 *****************************************************************************/
108 static int OpenFilter( vlc_object_t *p_this )
110 filter_t *p_filter = (filter_t*)p_this;
113 /* Check if we can handle that format.
114 * We could try to use a chroma filter if we can't. */
115 int in_chroma = p_filter->fmt_in.video.i_chroma;
116 int out_chroma = p_filter->fmt_out.video.i_chroma;
117 if( ( in_chroma != VLC_FOURCC('Y','U','V','A') &&
118 in_chroma != VLC_FOURCC('I','4','2','0') &&
119 in_chroma != VLC_FOURCC('Y','V','1','2') &&
120 in_chroma != VLC_FOURCC('Y','U','V','P') &&
121 in_chroma != VLC_FOURCC('R','G','B','A') ) ||
122 ( out_chroma != VLC_FOURCC('I','4','2','0') &&
123 out_chroma != VLC_FOURCC('Y','U','Y','2') &&
124 out_chroma != VLC_FOURCC('Y','V','1','2') &&
125 out_chroma != VLC_FOURCC('U','Y','V','Y') &&
126 out_chroma != VLC_FOURCC('Y','V','Y','U') &&
127 out_chroma != VLC_FOURCC('R','V','1','6') &&
128 out_chroma != VLC_FOURCC('R','V','2','4') &&
129 out_chroma != VLC_FOURCC('R','V','3','2') ) )
134 /* Allocate the memory needed to store the decoder's structure */
135 if( ( p_filter->p_sys = p_sys =
136 (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
140 p_filter->pf_video_blend = Blend;
142 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
143 (char *)&p_filter->fmt_in.video.i_chroma,
144 (char *)&p_filter->fmt_out.video.i_chroma );
149 /*****************************************************************************
150 * CloseFilter: clean up the filter
151 *****************************************************************************/
152 static void CloseFilter( vlc_object_t *p_this )
154 filter_t *p_filter = (filter_t*)p_this;
155 filter_sys_t *p_sys = p_filter->p_sys;
160 /****************************************************************************
161 * Blend: the whole thing
162 ****************************************************************************
163 * This function is called just after the thread is launched.
164 ****************************************************************************/
165 static void Blend( filter_t *p_filter, picture_t *p_dst,
166 picture_t *p_dst_orig, picture_t *p_src,
167 int i_x_offset, int i_y_offset, int i_alpha )
169 int i_width, i_height;
171 if( i_alpha == 0 ) return;
173 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
174 (int)p_filter->fmt_in.video.i_visible_width);
176 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
177 (int)p_filter->fmt_in.video.i_visible_height);
179 if( i_width <= 0 || i_height <= 0 ) return;
182 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
183 (char *)&p_filter->fmt_in.video.i_chroma,
184 (char *)&p_filter->fmt_out.video.i_chroma );
187 switch( p_filter->fmt_in.video.i_chroma )
189 case VLC_FOURCC('Y','U','V','A'):
190 switch( p_filter->fmt_out.video.i_chroma )
192 case VLC_FOURCC('I','4','2','0'):
193 case VLC_FOURCC('Y','V','1','2'):
194 BlendI420( p_filter, p_dst, p_dst_orig, p_src,
195 i_x_offset, i_y_offset,
196 i_width, i_height, i_alpha );
198 case VLC_FOURCC('Y','U','Y','2'):
199 case VLC_FOURCC('U','Y','V','Y'):
200 case VLC_FOURCC('Y','V','Y','U'):
201 BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
202 i_x_offset, i_y_offset,
203 i_width, i_height, i_alpha );
205 case VLC_FOURCC('R','V','1','6'):
206 BlendR16( p_filter, p_dst, p_dst_orig, p_src,
207 i_x_offset, i_y_offset,
208 i_width, i_height, i_alpha );
210 case VLC_FOURCC('R','V','2','4'):
211 case VLC_FOURCC('R','V','3','2'):
212 BlendR24( p_filter, p_dst, p_dst_orig, p_src,
213 i_x_offset, i_y_offset,
214 i_width, i_height, i_alpha );
217 case VLC_FOURCC('Y','U','V','P'):
218 switch( p_filter->fmt_out.video.i_chroma )
220 case VLC_FOURCC('I','4','2','0'):
221 case VLC_FOURCC('Y','V','1','2'):
222 BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
223 i_x_offset, i_y_offset,
224 i_width, i_height, i_alpha );
226 case VLC_FOURCC('Y','U','Y','2'):
227 case VLC_FOURCC('U','Y','V','Y'):
228 case VLC_FOURCC('Y','V','Y','U'):
229 BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
230 i_x_offset, i_y_offset,
231 i_width, i_height, i_alpha );
233 case VLC_FOURCC('R','V','1','6'):
234 case VLC_FOURCC('R','V','2','4'):
235 case VLC_FOURCC('R','V','3','2'):
236 BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
237 i_x_offset, i_y_offset,
238 i_width, i_height, i_alpha );
241 case VLC_FOURCC('Y','V','1','2'):
242 case VLC_FOURCC('I','4','2','0'):
243 switch( p_filter->fmt_out.video.i_chroma )
245 case VLC_FOURCC('I','4','2','0'):
246 case VLC_FOURCC('Y','V','1','2'):
247 if( i_alpha == 0xff )
248 BlendI420I420_no_alpha(
249 p_filter, p_dst, p_dst_orig, p_src,
250 i_x_offset, i_y_offset,
253 BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
254 i_x_offset, i_y_offset,
255 i_width, i_height, i_alpha );
257 case VLC_FOURCC('Y','U','Y','2'):
258 case VLC_FOURCC('U','Y','V','Y'):
259 case VLC_FOURCC('Y','V','Y','U'):
260 BlendI420YUVPacked( p_filter, p_dst, p_dst_orig, p_src,
261 i_x_offset, i_y_offset,
262 i_width, i_height, i_alpha );
264 case VLC_FOURCC('R','V','1','6'):
265 BlendI420R16( p_filter, p_dst, p_dst_orig, p_src,
266 i_x_offset, i_y_offset,
267 i_width, i_height, i_alpha );
269 case VLC_FOURCC('R','V','2','4'):
270 case VLC_FOURCC('R','V','3','2'):
271 BlendI420R24( p_filter, p_dst, p_dst_orig, p_src,
272 i_x_offset, i_y_offset,
273 i_width, i_height, i_alpha );
276 case VLC_FOURCC('R','G','B','A'):
277 switch( p_filter->fmt_out.video.i_chroma )
279 case VLC_FOURCC('I','4','2','0'):
280 case VLC_FOURCC('Y','V','1','2'):
281 BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
282 i_x_offset, i_y_offset,
283 i_width, i_height, i_alpha );
285 case VLC_FOURCC('Y','U','Y','2'):
286 case VLC_FOURCC('U','Y','V','Y'):
287 case VLC_FOURCC('Y','V','Y','U'):
288 BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
289 i_x_offset, i_y_offset,
290 i_width, i_height, i_alpha );
292 case VLC_FOURCC('R','V','2','4'):
293 case VLC_FOURCC('R','V','3','2'):
294 BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
295 i_x_offset, i_y_offset,
296 i_width, i_height, i_alpha );
298 case VLC_FOURCC('R','V','1','6'):
299 BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
300 i_x_offset, i_y_offset,
301 i_width, i_height, i_alpha );
306 msg_Dbg( p_filter, "no matching alpha blending routine "
307 "(chroma: %4.4s -> %4.4s)",
308 (char *)&p_filter->fmt_in.video.i_chroma,
309 (char *)&p_filter->fmt_out.video.i_chroma );
312 /***********************************************************************
314 ***********************************************************************/
315 static inline uint8_t vlc_uint8( int v )
324 #define MAX_TRANS 255
327 static inline int vlc_blend( int v1, int v2, int a )
329 /* TODO bench if the tests really increase speed */
332 else if( a == MAX_TRANS )
334 return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
337 static inline int vlc_alpha( int t, int a )
339 return (t * a) / 255;
342 static inline void yuv_to_rgb( int *r, int *g, int *b,
343 uint8_t y1, uint8_t u1, uint8_t v1 )
345 /* macros used for YUV pixel conversions */
346 # define SCALEBITS 10
347 # define ONE_HALF (1 << (SCALEBITS - 1))
348 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
350 int y, cb, cr, r_add, g_add, b_add;
354 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
355 g_add = - FIX(0.34414*255.0/224.0) * cb
356 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
357 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
358 y = (y1 - 16) * FIX(255.0/219.0);
359 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
360 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
361 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
367 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
368 int r, int g, int b )
370 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
371 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
372 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
375 static uint8_t *vlc_plane_start( int *pi_pitch,
376 picture_t *p_picture,
378 int i_x_offset, int i_y_offset,
379 const video_format_t *p_fmt,
382 const int i_pitch = p_picture->p[i_plane].i_pitch;
383 uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
385 const int i_dx = ( i_x_offset + p_fmt->i_x_offset ) / r;
386 const int i_dy = ( i_y_offset + p_fmt->i_y_offset ) / r;
390 return &p_pixels[ i_dy * i_pitch + i_dx ];
393 /***********************************************************************
395 ***********************************************************************/
396 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
397 picture_t *p_dst_orig, picture_t *p_src,
398 int i_x_offset, int i_y_offset,
399 int i_width, int i_height, int i_alpha )
401 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
402 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
403 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
404 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
406 int i_x, i_y, i_trans = 0;
407 bool b_even_scanline = i_y_offset % 2;
409 p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
410 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
411 p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
412 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
413 p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
414 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
416 p_src1_y = vlc_plane_start( &i_src1_pitch, p_dst_orig, Y_PLANE,
417 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
418 p_src1_u = vlc_plane_start( NULL, p_dst_orig, U_PLANE,
419 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
420 p_src1_v = vlc_plane_start( NULL, p_dst_orig, V_PLANE,
421 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
423 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
424 0, 0, &p_filter->fmt_in.video, 1 );
425 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
426 0, 0, &p_filter->fmt_in.video, 2 );
427 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
428 0, 0, &p_filter->fmt_in.video, 2 );
429 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
430 0, 0, &p_filter->fmt_in.video, 1 );
432 /* Draw until we reach the bottom of the subtitle */
433 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
434 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
435 p_src2_y += i_src2_pitch,
436 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
437 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
438 p_src2_u += i_src2_pitch,
439 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
440 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
441 p_src2_v += i_src2_pitch )
443 b_even_scanline = !b_even_scanline;
445 /* Draw until we reach the end of the line */
446 for( i_x = 0; i_x < i_width; i_x++ )
449 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
455 p_dst_y[i_x] = vlc_blend( p_src2_y[i_x], p_src1_y[i_x], i_trans );
456 if( b_even_scanline && i_x % 2 == 0 )
458 p_dst_u[i_x/2] = vlc_blend( p_src2_u[i_x], p_src1_u[i_x/2], i_trans );
459 p_dst_v[i_x/2] = vlc_blend( p_src2_v[i_x], p_src1_v[i_x/2], i_trans );
465 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
466 picture_t *p_dst_orig, picture_t *p_src,
467 int i_x_offset, int i_y_offset,
468 int i_width, int i_height, int i_alpha )
470 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
471 uint8_t *p_dst, *p_src1, *p_src2_y;
472 uint8_t *p_src2_u, *p_src2_v;
474 int i_x, i_y, i_pix_pitch, i_trans = 0;
477 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
478 i_dst_pitch = p_dst_pic->p->i_pitch;
479 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
480 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
481 p_dst_pic->p->i_pitch *
482 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
484 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
485 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
486 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
487 p_dst_orig->p->i_pitch *
488 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
490 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
491 0, 0, &p_filter->fmt_in.video, 1 );
492 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
493 0, 0, &p_filter->fmt_in.video, 2 );
494 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
495 0, 0, &p_filter->fmt_in.video, 2 );
496 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
497 0, 0, &p_filter->fmt_in.video, 1 );
499 /* Draw until we reach the bottom of the subtitle */
500 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
501 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
502 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
503 p_src2_v += i_src2_pitch )
505 /* Draw until we reach the end of the line */
506 for( i_x = 0; i_x < i_width; i_x++ )
509 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
514 /* FIXME: do the blending
515 * FIXME use rgb shift (when present) */
516 yuv_to_rgb( &r, &g, &b,
517 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
519 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
524 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
525 picture_t *p_dst_orig, picture_t *p_src,
526 int i_x_offset, int i_y_offset,
527 int i_width, int i_height, int i_alpha )
529 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
530 uint8_t *p_dst, *p_src1, *p_src2_y;
531 uint8_t *p_src2_u, *p_src2_v;
533 int i_x, i_y, i_pix_pitch, i_trans = 0;
536 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
537 i_dst_pitch = p_dst_pic->p->i_pitch;
538 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
539 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
540 p_dst_pic->p->i_pitch *
541 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
543 i_src1_pitch = p_dst_orig->p->i_pitch;
544 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
545 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
546 p_dst_orig->p->i_pitch *
547 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
549 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
550 0, 0, &p_filter->fmt_in.video, 1 );
551 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
552 0, 0, &p_filter->fmt_in.video, 2 );
553 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
554 0, 0, &p_filter->fmt_in.video, 2 );
555 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
556 0, 0, &p_filter->fmt_in.video, 1 );
558 if( (i_pix_pitch == 4)
559 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
563 ** if picture pixels are 32 bits long and lines addresses are 32 bit
564 ** aligned, optimize rendering
566 uint32_t *p32_dst = (uint32_t *)p_dst;
567 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
568 uint32_t *p32_src1 = (uint32_t *)p_src1;
569 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
571 int i_rshift, i_gshift, i_bshift;
572 uint32_t i_rmask, i_gmask, i_bmask;
574 if( p_dst_pic->p_heap )
576 i_rmask = p_dst_pic->p_heap->i_rmask;
577 i_gmask = p_dst_pic->p_heap->i_gmask;
578 i_bmask = p_dst_pic->p_heap->i_bmask;
579 i_rshift = p_dst_pic->p_heap->i_lrshift;
580 i_gshift = p_dst_pic->p_heap->i_lgshift;
581 i_bshift = p_dst_pic->p_heap->i_lbshift;
585 i_rmask = p_dst_pic->format.i_rmask;
586 i_gmask = p_dst_pic->format.i_gmask;
587 i_bmask = p_dst_pic->format.i_bmask;
589 if( (i_rmask == 0x00FF0000)
590 && (i_gmask == 0x0000FF00)
591 && (i_bmask == 0x000000FF) )
593 /* X8R8G8B8 pixel layout */
598 else if( (i_rmask == 0xFF000000)
599 && (i_gmask == 0x00FF0000)
600 && (i_bmask == 0x0000FF00) )
602 /* R8G8B8X8 pixel layout */
612 /* Draw until we reach the bottom of the subtitle */
613 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
614 p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
615 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
616 p_src2_v += i_src2_pitch )
618 /* Draw until we reach the end of the line */
619 for( i_x = 0; i_x < i_width; i_x++ )
622 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
626 if( i_trans == MAX_TRANS )
628 /* Completely opaque. Completely overwrite underlying pixel */
629 yuv_to_rgb( &r, &g, &b,
630 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
632 p32_dst[i_x] = (r<<i_rshift) |
639 uint32_t i_pix_src1 = p32_src1[i_x];
640 yuv_to_rgb( &r, &g, &b,
641 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
643 p32_dst[i_x] = ( vlc_blend( r, (i_pix_src1 & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
644 ( vlc_blend( g, (i_pix_src1 & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
645 ( vlc_blend( b, (i_pix_src1 & i_bmask)>>i_bshift, i_trans ) << i_bshift );
652 int i_rindex, i_bindex, i_gindex;
653 uint32_t i_rmask, i_gmask, i_bmask;
657 i_rmask = p_dst_pic->format.i_rmask;
658 i_gmask = p_dst_pic->format.i_gmask;
659 i_bmask = p_dst_pic->format.i_bmask;
662 ** quick and dirty way to get byte index from mask
663 ** will only work correctly if mask are 8 bit aligned
664 ** and are 8 bit long
666 #ifdef WORDS_BIGENDIAN
667 i_rindex = ((i_rmask>>16) & 1)
670 i_gindex = ((i_gmask>>16) & 1)
673 i_bindex = ((i_bmask>>16) & 1)
677 i_rindex = ((i_rmask>>24) & 3)
678 | ((i_rmask>>16) & 2)
679 | ((i_rmask>>8) & 1);
680 i_gindex = ((i_gmask>>24) & 3)
681 | ((i_gmask>>16) & 2)
682 | ((i_gmask>>8) & 1);
683 i_bindex = ((i_bmask>>24) & 3)
684 | ((i_bmask>>16) & 2)
685 | ((i_bmask>>8) & 1);
688 /* Draw until we reach the bottom of the subtitle */
689 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
690 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
691 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
692 p_src2_v += i_src2_pitch )
694 /* Draw until we reach the end of the line */
695 for( i_x = 0; i_x < i_width; i_x++ )
698 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
702 const int i_pos = i_x * i_pix_pitch;
703 if( i_trans == MAX_TRANS )
706 /* Completely opaque. Completely overwrite underlying pixel */
707 yuv_to_rgb( &r, &g, &b,
708 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
710 p_dst[i_pos + i_rindex ] = r;
711 p_dst[i_pos + i_gindex ] = g;
712 p_dst[i_pos + i_bindex ] = b;
716 int i_rpos = i_pos + i_rindex;
717 int i_gpos = i_pos + i_gindex;
718 int i_bpos = i_pos + i_bindex;
721 yuv_to_rgb( &r, &g, &b,
722 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
724 p_dst[i_rpos] = vlc_blend( r, p_src1[i_rpos], i_trans );
725 p_dst[i_gpos] = vlc_blend( g, p_src1[i_gpos], i_trans );
726 p_dst[i_bpos] = vlc_blend( b, p_src1[i_gpos], i_trans );
733 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
734 picture_t *p_dst_orig, picture_t *p_src,
735 int i_x_offset, int i_y_offset,
736 int i_width, int i_height, int i_alpha )
738 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
739 uint8_t *p_dst, *p_src1, *p_src2_y;
740 uint8_t *p_src2_u, *p_src2_v;
742 int i_x, i_y, i_pix_pitch, i_trans = 0;
743 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
744 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
746 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
752 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
758 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
766 i_dst_pitch = p_dst_pic->p->i_pitch;
767 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
768 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
769 p_dst_pic->p->i_pitch *
770 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
772 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
773 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
774 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
775 p_dst_orig->p->i_pitch *
776 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
778 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
779 0, 0, &p_filter->fmt_in.video, 1 );
780 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
781 0, 0, &p_filter->fmt_in.video, 2 );
782 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
783 0, 0, &p_filter->fmt_in.video, 2 );
784 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
785 0, 0, &p_filter->fmt_in.video, 1 );
787 i_width &= ~1; /* Needs to be a multiple of 2 */
789 /* Draw until we reach the bottom of the subtitle */
790 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
791 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
792 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
793 p_src2_v += i_src2_pitch )
795 /* Draw until we reach the end of the line */
796 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
798 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
803 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_trans );
808 /* FIXME what's with 0xaa ? */
809 if( p_trans[i_x+1] > 0xaa )
811 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
812 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
819 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_trans );
820 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_trans );
825 /***********************************************************************
827 ***********************************************************************/
828 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
829 picture_t *p_dst_orig, picture_t *p_src,
830 int i_x_offset, int i_y_offset,
831 int i_width, int i_height, int i_alpha )
833 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
834 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
835 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
836 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
838 bool b_even_scanline = i_y_offset % 2;
840 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
841 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
842 p_filter->fmt_out.video.i_x_offset +
843 p_dst->p[Y_PLANE].i_pitch *
844 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
845 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
846 p_filter->fmt_out.video.i_x_offset/2 +
847 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
848 p_dst->p[U_PLANE].i_pitch;
849 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
850 p_filter->fmt_out.video.i_x_offset/2 +
851 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
852 p_dst->p[V_PLANE].i_pitch;
854 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
855 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
856 p_filter->fmt_out.video.i_x_offset +
857 p_dst_orig->p[Y_PLANE].i_pitch *
858 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
859 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
860 p_filter->fmt_out.video.i_x_offset/2 +
861 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
862 p_dst_orig->p[U_PLANE].i_pitch;
863 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
864 p_filter->fmt_out.video.i_x_offset/2 +
865 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
866 p_dst_orig->p[V_PLANE].i_pitch;
868 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
869 0, 0, &p_filter->fmt_in.video, 1 );
870 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
871 0, 0, &p_filter->fmt_in.video, 2 );
872 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
873 0, 0, &p_filter->fmt_in.video, 2 );
876 /* Draw until we reach the bottom of the subtitle */
877 for( i_y = 0; i_y < i_height; i_y++,
878 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
879 p_src2_y += i_src2_pitch )
881 if( b_even_scanline )
883 p_dst_u += i_dst_pitch/2;
884 p_dst_v += i_dst_pitch/2;
885 p_src1_u += i_src1_pitch/2;
886 p_src1_v += i_src1_pitch/2;
888 b_even_scanline = !b_even_scanline;
890 /* Draw until we reach the end of the line */
891 for( i_x = 0; i_x < i_width; i_x++ )
897 p_dst_y[i_x] = vlc_blend( p_src2_y[i_x], p_src1_y[i_x], i_alpha );
898 if( b_even_scanline && i_x % 2 == 0 )
900 p_dst_u[i_x/2] = vlc_blend( p_src2_u[i_x/2], p_src1_u[i_x/2], i_alpha );
901 p_dst_v[i_x/2] = vlc_blend( p_src2_v[i_x/2], p_src1_v[i_x/2], i_alpha );
906 p_src2_u += i_src2_pitch/2;
907 p_src2_v += i_src2_pitch/2;
911 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
912 picture_t *p_dst_orig, picture_t *p_src,
913 int i_x_offset, int i_y_offset,
914 int i_width, int i_height )
916 int i_src2_pitch, i_dst_pitch;
917 uint8_t *p_src2_y, *p_dst_y;
918 uint8_t *p_src2_u, *p_dst_u;
919 uint8_t *p_src2_v, *p_dst_v;
921 bool b_even_scanline = i_y_offset % 2;
923 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
924 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
925 p_filter->fmt_out.video.i_x_offset +
926 p_dst->p[Y_PLANE].i_pitch *
927 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
928 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
929 p_filter->fmt_out.video.i_x_offset/2 +
930 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
931 p_dst->p[U_PLANE].i_pitch;
932 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
933 p_filter->fmt_out.video.i_x_offset/2 +
934 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
935 p_dst->p[V_PLANE].i_pitch;
937 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
938 0, 0, &p_filter->fmt_in.video, 1 );
939 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
940 0, 0, &p_filter->fmt_in.video, 2 );
941 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
942 0, 0, &p_filter->fmt_in.video, 2 );
946 /* Draw until we reach the bottom of the subtitle */
947 for( i_y = 0; i_y < i_height;
948 i_y++, p_dst_y += i_dst_pitch, p_src2_y += i_src2_pitch )
950 /* Completely opaque. Completely overwrite underlying pixel */
951 vlc_memcpy( p_dst_y, p_src2_y, i_width );
952 if( b_even_scanline )
954 p_dst_u += i_dst_pitch/2;
955 p_dst_v += i_dst_pitch/2;
959 vlc_memcpy( p_dst_u, p_src2_u, i_width/2 );
960 vlc_memcpy( p_dst_v, p_src2_v, i_width/2 );
962 b_even_scanline = !b_even_scanline;
965 p_src2_u += i_src2_pitch/2;
966 p_src2_v += i_src2_pitch/2;
971 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
972 picture_t *p_dst_orig, picture_t *p_src,
973 int i_x_offset, int i_y_offset,
974 int i_width, int i_height, int i_alpha )
976 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
977 uint8_t *p_dst, *p_src1, *p_src2_y;
978 uint8_t *p_src2_u, *p_src2_v;
979 int i_x, i_y, i_pix_pitch;
982 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
983 i_dst_pitch = p_dst_pic->p->i_pitch;
984 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
985 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
986 p_dst_pic->p->i_pitch *
987 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
989 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
990 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
991 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
992 p_dst_orig->p->i_pitch *
993 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
995 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
996 0, 0, &p_filter->fmt_in.video, 1 );
997 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
998 0, 0, &p_filter->fmt_in.video, 2 );
999 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
1000 0, 0, &p_filter->fmt_in.video, 2 );
1002 /* Draw until we reach the bottom of the subtitle */
1003 for( i_y = 0; i_y < i_height; i_y++,
1004 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1005 p_src2_y += i_src2_pitch )
1007 /* Draw until we reach the end of the line */
1008 for( i_x = 0; i_x < i_width; i_x++ )
1010 if( i_alpha == MAX_TRANS )
1012 /* Completely opaque. Completely overwrite underlying pixel */
1013 yuv_to_rgb( &r, &g, &b,
1014 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1016 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1021 /* FIXME: do the blending
1022 * FIXME use rgb shifts */
1023 yuv_to_rgb( &r, &g, &b,
1024 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1026 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1030 p_src2_u += i_src2_pitch/2;
1031 p_src2_v += i_src2_pitch/2;
1036 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1037 picture_t *p_dst_orig, picture_t *p_src,
1038 int i_x_offset, int i_y_offset,
1039 int i_width, int i_height, int i_alpha )
1041 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1042 uint8_t *p_dst, *p_src1, *p_src2_y;
1043 uint8_t *p_src2_u, *p_src2_v;
1044 int i_x, i_y, i_pix_pitch;
1047 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1048 i_dst_pitch = p_dst_pic->p->i_pitch;
1049 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1050 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1051 p_dst_pic->p->i_pitch *
1052 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1054 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1055 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1056 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1057 p_dst_orig->p->i_pitch *
1058 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1060 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
1061 0, 0, &p_filter->fmt_in.video, 1 );
1062 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
1063 0, 0, &p_filter->fmt_in.video, 2 );
1064 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
1065 0, 0, &p_filter->fmt_in.video, 2 );
1068 /* Draw until we reach the bottom of the subtitle */
1069 for( i_y = 0; i_y < i_height; i_y++,
1070 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1071 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1072 p_src2_v += i_src2_pitch )
1074 /* Draw until we reach the end of the line */
1075 for( i_x = 0; i_x < i_width; i_x++ )
1081 yuv_to_rgb( &r, &g, &b,
1082 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1084 p_dst[i_x * i_pix_pitch + 0] = vlc_blend( r, p_src1[i_x * i_pix_pitch + 0], i_alpha );
1085 p_dst[i_x * i_pix_pitch + 1] = vlc_blend( g, p_src1[i_x * i_pix_pitch + 1], i_alpha );
1086 p_dst[i_x * i_pix_pitch + 2] = vlc_blend( b, p_src1[i_x * i_pix_pitch + 2], i_alpha );
1090 p_src2_u += i_src2_pitch/2;
1091 p_src2_v += i_src2_pitch/2;
1096 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1097 picture_t *p_dst_orig, picture_t *p_src,
1098 int i_x_offset, int i_y_offset,
1099 int i_width, int i_height, int i_alpha )
1101 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1102 uint8_t *p_dst, *p_src1, *p_src2_y;
1103 uint8_t *p_src2_u, *p_src2_v;
1104 int i_x, i_y, i_pix_pitch;
1105 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1106 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1108 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1114 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1120 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1128 i_dst_pitch = p_dst_pic->p->i_pitch;
1129 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1130 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1131 p_dst_pic->p->i_pitch *
1132 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1134 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1135 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1136 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1137 p_dst_orig->p->i_pitch *
1138 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1140 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
1141 0, 0, &p_filter->fmt_in.video, 1 );
1142 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
1143 0, 0, &p_filter->fmt_in.video, 2 );
1144 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
1145 0, 0, &p_filter->fmt_in.video, 2 );
1147 i_width &= ~1; /* Needs to be a multiple of 2 */
1149 /* Draw until we reach the bottom of the subtitle */
1150 for( i_y = 0; i_y < i_height; i_y++,
1151 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1152 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1153 p_src2_v += i_src2_pitch )
1155 /* Draw until we reach the end of the line */
1156 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1162 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_alpha );
1165 uint16_t i_u = p_src2_u[i_x/2];
1166 uint16_t i_v = p_src2_v[i_x/2];
1167 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_alpha );
1168 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_alpha );
1173 p_src2_u += i_src2_pitch/2;
1174 p_src2_v += i_src2_pitch/2;
1179 /***********************************************************************
1181 ***********************************************************************/
1182 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1183 picture_t *p_dst_orig, picture_t *p_src,
1184 int i_x_offset, int i_y_offset,
1185 int i_width, int i_height, int i_alpha )
1187 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1188 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1189 uint8_t *p_src1_u, *p_dst_u;
1190 uint8_t *p_src1_v, *p_dst_v;
1191 int i_x, i_y, i_trans;
1192 bool b_even_scanline = i_y_offset % 2;
1194 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1195 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1196 p_filter->fmt_out.video.i_x_offset +
1197 p_dst->p[Y_PLANE].i_pitch *
1198 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1199 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1200 p_filter->fmt_out.video.i_x_offset/2 +
1201 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1202 p_dst->p[U_PLANE].i_pitch;
1203 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1204 p_filter->fmt_out.video.i_x_offset/2 +
1205 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1206 p_dst->p[V_PLANE].i_pitch;
1208 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1209 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1210 p_filter->fmt_out.video.i_x_offset +
1211 p_dst_orig->p[Y_PLANE].i_pitch *
1212 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1213 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1214 p_filter->fmt_out.video.i_x_offset/2 +
1215 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1216 p_dst_orig->p[U_PLANE].i_pitch;
1217 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1218 p_filter->fmt_out.video.i_x_offset/2 +
1219 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1220 p_dst_orig->p[V_PLANE].i_pitch;
1222 i_src2_pitch = p_src->p->i_pitch;
1223 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1224 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1226 const uint8_t *p_trans = p_src2;
1227 #define p_pal p_filter->fmt_in.video.p_palette->palette
1229 /* Draw until we reach the bottom of the subtitle */
1230 for( i_y = 0; i_y < i_height; i_y++,
1231 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1232 p_src2 += i_src2_pitch,
1233 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1234 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1235 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1236 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1238 b_even_scanline = !b_even_scanline;
1240 /* Draw until we reach the end of the line */
1241 for( i_x = 0; i_x < i_width; i_x++ )
1243 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1248 p_dst_y[i_x] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1_y[i_x], i_trans );
1249 if( b_even_scanline && ((i_x % 2) == 0) )
1251 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src2[i_x]][1], p_src1_u[i_x/2], i_trans );
1252 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src2[i_x]][2], p_src1_v[i_x/2], i_trans );
1259 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1260 picture_t *p_dst_orig, picture_t *p_src,
1261 int i_x_offset, int i_y_offset,
1262 int i_width, int i_height, int i_alpha )
1264 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1265 uint8_t *p_src1, *p_src2, *p_dst;
1266 int i_x, i_y, i_pix_pitch, i_trans;
1267 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1268 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1270 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1276 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1282 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1290 i_dst_pitch = p_dst_pic->p->i_pitch;
1291 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1292 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1293 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1295 i_src1_pitch = p_dst_orig->p->i_pitch;
1296 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1297 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1298 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1300 i_src2_pitch = p_src->p->i_pitch;
1301 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1302 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1304 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1306 const uint8_t *p_trans = p_src2;
1307 #define p_pal p_filter->fmt_in.video.p_palette->palette
1309 /* Draw until we reach the bottom of the subtitle */
1310 for( i_y = 0; i_y < i_height; i_y++,
1311 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1313 /* Draw until we reach the end of the line */
1314 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1316 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1321 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1[i_x * 2 + i_l_offset], i_trans );
1326 if( p_trans[i_x+1] > 0xaa )
1328 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1329 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1333 i_u = p_pal[p_src2[i_x]][1];
1334 i_v = p_pal[p_src2[i_x]][2];
1337 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_trans );
1338 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_trans );
1345 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1346 picture_t *p_dst_orig, picture_t *p_src,
1347 int i_x_offset, int i_y_offset,
1348 int i_width, int i_height, int i_alpha )
1350 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1351 uint8_t *p_src1, *p_src2, *p_dst;
1352 int i_x, i_y, i_pix_pitch, i_trans;
1354 video_palette_t rgbpalette;
1356 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1357 i_dst_pitch = p_dst_pic->p->i_pitch;
1358 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1359 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1360 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1362 i_src1_pitch = p_dst_orig->p->i_pitch;
1363 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1364 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1365 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1367 i_src2_pitch = p_src->p->i_pitch;
1368 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1369 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1371 const uint8_t *p_trans = p_src2;
1372 #define p_pal p_filter->fmt_in.video.p_palette->palette
1373 #define rgbpal rgbpalette.palette
1375 /* Convert palette first */
1376 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1379 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1381 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1383 *(uint16_t *)rgbpal[i_y] =
1384 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1388 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1392 /* Draw until we reach the bottom of the subtitle */
1393 for( i_y = 0; i_y < i_height; i_y++,
1394 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1396 /* Draw until we reach the end of the line */
1397 for( i_x = 0; i_x < i_width; i_x++ )
1399 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1403 if( i_trans == MAX_TRANS ||
1404 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1406 /* FIXME implement blending for RV16 */
1407 /* Completely opaque. Completely overwrite underlying pixel */
1408 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1409 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1410 if( p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','1','6') )
1411 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1416 p_dst[i_x * i_pix_pitch + 0] = vlc_blend( rgbpal[p_src2[i_x]][0], p_src1[i_x * i_pix_pitch + 0], i_trans );
1417 p_dst[i_x * i_pix_pitch + 1] = vlc_blend( rgbpal[p_src2[i_x]][1], p_src1[i_x * i_pix_pitch + 1], i_trans );
1418 p_dst[i_x * i_pix_pitch + 2] = vlc_blend( rgbpal[p_src2[i_x]][2], p_src1[i_x * i_pix_pitch + 2], i_trans );
1426 /***********************************************************************
1428 ***********************************************************************/
1429 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1430 picture_t *p_dst_orig, picture_t *p_src,
1431 int i_x_offset, int i_y_offset,
1432 int i_width, int i_height, int i_alpha )
1434 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1435 uint8_t *p_src1_y, *p_dst_y;
1436 uint8_t *p_src1_u, *p_dst_u;
1437 uint8_t *p_src1_v, *p_dst_v;
1439 int i_x, i_y, i_trans;
1442 bool b_even_scanline = i_y_offset % 2;
1444 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1445 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1446 p_filter->fmt_out.video.i_x_offset +
1447 p_dst->p[Y_PLANE].i_pitch *
1448 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1449 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1450 p_filter->fmt_out.video.i_x_offset/2 +
1451 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1452 p_dst->p[U_PLANE].i_pitch;
1453 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1454 p_filter->fmt_out.video.i_x_offset/2 +
1455 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1456 p_dst->p[V_PLANE].i_pitch;
1458 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1459 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1460 p_filter->fmt_out.video.i_x_offset +
1461 p_dst_orig->p[Y_PLANE].i_pitch *
1462 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1463 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1464 p_filter->fmt_out.video.i_x_offset/2 +
1465 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1466 p_dst_orig->p[U_PLANE].i_pitch;
1467 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1468 p_filter->fmt_out.video.i_x_offset/2 +
1469 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1470 p_dst_orig->p[V_PLANE].i_pitch;
1472 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1473 i_src2_pitch = p_src->p->i_pitch;
1474 p_src2 = p_src->p->p_pixels +
1475 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1476 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1479 /* Draw until we reach the bottom of the subtitle */
1480 for( i_y = 0; i_y < i_height; i_y++,
1481 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1482 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1483 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1484 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1485 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1486 p_src2 += i_src2_pitch )
1488 b_even_scanline = !b_even_scanline;
1490 /* Draw until we reach the end of the line */
1491 for( i_x = 0; i_x < i_width; i_x++ )
1493 const int R = p_src2[i_x * i_src_pix_pitch + 0];
1494 const int G = p_src2[i_x * i_src_pix_pitch + 1];
1495 const int B = p_src2[i_x * i_src_pix_pitch + 2];
1497 i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1502 rgb_to_yuv( &y, &u, &v, R, G, B );
1504 p_dst_y[i_x] = vlc_blend( y, p_src1_y[i_x], i_trans );
1505 if( b_even_scanline && i_x % 2 == 0 )
1507 p_dst_u[i_x/2] = vlc_blend( u, p_src1_u[i_x/2], i_trans );
1508 p_dst_v[i_x/2] = vlc_blend( v, p_src1_v[i_x/2], i_trans );
1514 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1515 picture_t *p_dst_orig, picture_t *p_src,
1516 int i_x_offset, int i_y_offset,
1517 int i_width, int i_height, int i_alpha )
1519 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1520 uint8_t *p_dst, *p_src1, *p_src2;
1521 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1523 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1524 i_dst_pitch = p_dst_pic->p->i_pitch;
1525 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1526 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1527 p_dst_pic->p->i_pitch *
1528 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1530 i_src1_pitch = p_dst_orig->p->i_pitch;
1531 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1532 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1533 p_dst_orig->p->i_pitch *
1534 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1536 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1537 i_src2_pitch = p_src->p->i_pitch;
1538 p_src2 = p_src->p->p_pixels +
1539 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1540 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1542 /* Draw until we reach the bottom of the subtitle */
1543 for( i_y = 0; i_y < i_height; i_y++,
1544 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1546 /* Draw until we reach the end of the line */
1547 for( i_x = 0; i_x < i_width; i_x++ )
1549 const int R = p_src2[i_x * i_src_pix_pitch + 0];
1550 const int G = p_src2[i_x * i_src_pix_pitch + 1];
1551 const int B = p_src2[i_x * i_src_pix_pitch + 2];
1553 i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1558 p_dst[i_x * i_pix_pitch + 0] = vlc_blend( R, p_src1[i_x * i_pix_pitch + 0], i_trans );
1559 p_dst[i_x * i_pix_pitch + 1] = vlc_blend( G, p_src1[i_x * i_pix_pitch + 1], i_trans );
1560 p_dst[i_x * i_pix_pitch + 2] = vlc_blend( B, p_src1[i_x * i_pix_pitch + 2], i_trans );
1565 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1566 picture_t *p_dst_orig, picture_t *p_src,
1567 int i_x_offset, int i_y_offset,
1568 int i_width, int i_height, int i_alpha )
1570 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1571 uint8_t *p_dst, *p_src1, *p_src2;
1572 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1575 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1576 i_dst_pitch = p_dst_pic->p->i_pitch;
1577 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1578 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1579 p_dst_pic->p->i_pitch *
1580 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1582 i_src1_pitch = p_dst_orig->p->i_pitch;
1583 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1584 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1585 p_dst_orig->p->i_pitch *
1586 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1588 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1589 i_src2_pitch = p_src->p->i_pitch;
1590 p_src2 = p_src->p->p_pixels +
1591 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1592 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1594 /* Draw until we reach the bottom of the subtitle */
1595 for( i_y = 0; i_y < i_height; i_y++,
1596 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1598 /* Draw until we reach the end of the line */
1599 for( i_x = 0; i_x < i_width; i_x++ )
1601 const int R = p_src2[i_x * i_src_pix_pitch + 0];
1602 const int G = p_src2[i_x * i_src_pix_pitch + 1];
1603 const int B = p_src2[i_x * i_src_pix_pitch + 2];
1605 i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1610 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1611 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1612 ( vlc_blend( R >> 3, ((i_pix )>> 11), i_trans ) << 11 ) |
1613 ( vlc_blend( G >> 2, ((i_pix & 0x07e0)>> 5), i_trans ) << 5 ) |
1614 ( vlc_blend( B >> 3, ((i_pix & 0x001f) ), i_trans ) );
1619 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1620 picture_t *p_dst_orig, picture_t *p_src,
1621 int i_x_offset, int i_y_offset,
1622 int i_width, int i_height, int i_alpha )
1624 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1625 uint8_t *p_dst, *p_src1, *p_src2;
1627 int i_x, i_y, i_pix_pitch, i_trans;
1628 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1629 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1632 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1638 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1644 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1652 i_dst_pitch = p_dst_pic->p->i_pitch;
1653 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1654 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1655 p_dst_pic->p->i_pitch *
1656 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1658 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1659 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1660 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1661 p_dst_orig->p->i_pitch *
1662 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1664 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1665 i_src2_pitch = p_src->p->i_pitch;
1666 p_src2 = p_src->p->p_pixels +
1667 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1668 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1670 i_width &= ~1; /* Needs to be a multiple of 2 */
1672 /* Draw until we reach the bottom of the subtitle */
1673 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
1674 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1675 p_src2 += i_src2_pitch )
1677 /* Draw until we reach the end of the line */
1678 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1680 const int R = p_src2[i_x * i_src_pix_pitch + 0];
1681 const int G = p_src2[i_x * i_src_pix_pitch + 1];
1682 const int B = p_src2[i_x * i_src_pix_pitch + 2];
1684 i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1689 rgb_to_yuv( &y, &u, &v, R, G, B );
1690 p_dst[i_x * 2 + i_l_offset] = vlc_blend( y, p_src1[i_x * 2 + i_l_offset], i_trans );
1693 p_dst[i_x * 2 + i_u_offset] = vlc_blend( u, p_src1[i_x * 2 + i_u_offset], i_trans );
1694 p_dst[i_x * 2 + i_v_offset] = vlc_blend( v, p_src1[i_x * 2 + i_v_offset], i_trans );