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 *****************************************************************************/
30 #include "vlc_filter.h"
32 /*****************************************************************************
33 * filter_sys_t : filter descriptor
34 *****************************************************************************/
40 /****************************************************************************
42 ****************************************************************************/
43 static int OpenFilter ( vlc_object_t * );
44 static void CloseFilter( vlc_object_t * );
46 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
49 /* TODO i_alpha support for BlendR16 */
51 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
52 int, int, int, int, int );
53 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
54 int, int, int, int, int );
55 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
56 int, int, int, int, int );
57 static void BlendYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
58 int, int, int, int, int );
61 static void BlendI420I420( filter_t *, picture_t *, picture_t *, picture_t *,
62 int, int, int, int, int );
63 static void BlendI420I420_no_alpha(
64 filter_t *, picture_t *, picture_t *, picture_t *,
66 static void BlendI420R16( filter_t *, picture_t *, picture_t *, picture_t *,
67 int, int, int, int, int );
68 static void BlendI420R24( filter_t *, picture_t *, picture_t *, picture_t *,
69 int, int, int, int, int );
70 static void BlendI420YUVPacked( filter_t *, picture_t *, picture_t *,
71 picture_t *, int, int, int, int, int );
74 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
75 int, int, int, int, int );
76 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
77 int, int, int, int, int );
78 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
79 int, int, int, int, int );
82 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
83 int, int, int, int, int );
84 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
85 picture_t *, int, int, int, int, int );
86 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
87 int, int, int, int, int );
88 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
89 int, int, int, int, int );
91 /*****************************************************************************
93 *****************************************************************************/
95 set_description( _("Video pictures blending") );
96 set_capability( "video blending", 100 );
97 set_callbacks( OpenFilter, CloseFilter );
100 /*****************************************************************************
101 * OpenFilter: probe the filter and return score
102 *****************************************************************************/
103 static int OpenFilter( vlc_object_t *p_this )
105 filter_t *p_filter = (filter_t*)p_this;
108 /* Check if we can handle that format.
109 * We could try to use a chroma filter if we can't. */
110 int in_chroma = p_filter->fmt_in.video.i_chroma;
111 int out_chroma = p_filter->fmt_out.video.i_chroma;
112 if( ( in_chroma != VLC_FOURCC('Y','U','V','A') &&
113 in_chroma != VLC_FOURCC('I','4','2','0') &&
114 in_chroma != VLC_FOURCC('Y','V','1','2') &&
115 in_chroma != VLC_FOURCC('Y','U','V','P') &&
116 in_chroma != VLC_FOURCC('R','G','B','A') ) ||
117 ( out_chroma != VLC_FOURCC('I','4','2','0') &&
118 out_chroma != VLC_FOURCC('Y','U','Y','2') &&
119 out_chroma != VLC_FOURCC('Y','V','1','2') &&
120 out_chroma != VLC_FOURCC('U','Y','V','Y') &&
121 out_chroma != VLC_FOURCC('Y','V','Y','U') &&
122 out_chroma != VLC_FOURCC('R','V','1','6') &&
123 out_chroma != VLC_FOURCC('R','V','2','4') &&
124 out_chroma != VLC_FOURCC('R','V','3','2') ) )
129 /* Allocate the memory needed to store the decoder's structure */
130 if( ( p_filter->p_sys = p_sys =
131 (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
133 msg_Err( p_filter, "out of memory" );
138 p_filter->pf_video_blend = Blend;
140 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
141 (char *)&p_filter->fmt_in.video.i_chroma,
142 (char *)&p_filter->fmt_out.video.i_chroma );
147 /*****************************************************************************
148 * CloseFilter: clean up the filter
149 *****************************************************************************/
150 static void CloseFilter( vlc_object_t *p_this )
152 filter_t *p_filter = (filter_t*)p_this;
153 filter_sys_t *p_sys = p_filter->p_sys;
158 /****************************************************************************
159 * Blend: the whole thing
160 ****************************************************************************
161 * This function is called just after the thread is launched.
162 ****************************************************************************/
163 static void Blend( filter_t *p_filter, picture_t *p_dst,
164 picture_t *p_dst_orig, picture_t *p_src,
165 int i_x_offset, int i_y_offset, int i_alpha )
167 int i_width, i_height;
169 if( i_alpha == 0 ) return;
171 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
172 (int)p_filter->fmt_in.video.i_visible_width);
174 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
175 (int)p_filter->fmt_in.video.i_visible_height);
177 if( i_width <= 0 || i_height <= 0 ) return;
180 printf( "chroma: %4.4s -> %4.4s\n",
181 (char *)&p_filter->fmt_in.video.i_chroma,
182 (char *)&p_filter->fmt_out.video.i_chroma );
185 switch( p_filter->fmt_in.video.i_chroma )
187 case VLC_FOURCC('Y','U','V','A'):
188 switch( p_filter->fmt_out.video.i_chroma )
190 case VLC_FOURCC('I','4','2','0'):
191 case VLC_FOURCC('Y','V','1','2'):
192 BlendI420( p_filter, p_dst, p_dst_orig, p_src,
193 i_x_offset, i_y_offset,
194 i_width, i_height, i_alpha );
196 case VLC_FOURCC('Y','U','Y','2'):
197 case VLC_FOURCC('U','Y','V','Y'):
198 case VLC_FOURCC('Y','V','Y','U'):
199 BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
200 i_x_offset, i_y_offset,
201 i_width, i_height, i_alpha );
203 case VLC_FOURCC('R','V','1','6'):
204 BlendR16( p_filter, p_dst, p_dst_orig, p_src,
205 i_x_offset, i_y_offset,
206 i_width, i_height, i_alpha );
208 case VLC_FOURCC('R','V','2','4'):
209 case VLC_FOURCC('R','V','3','2'):
210 BlendR24( p_filter, p_dst, p_dst_orig, p_src,
211 i_x_offset, i_y_offset,
212 i_width, i_height, i_alpha );
215 case VLC_FOURCC('Y','U','V','P'):
216 switch( p_filter->fmt_out.video.i_chroma )
218 case VLC_FOURCC('I','4','2','0'):
219 case VLC_FOURCC('Y','V','1','2'):
220 BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
221 i_x_offset, i_y_offset,
222 i_width, i_height, i_alpha );
224 case VLC_FOURCC('Y','U','Y','2'):
225 case VLC_FOURCC('U','Y','V','Y'):
226 case VLC_FOURCC('Y','V','Y','U'):
227 BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
228 i_x_offset, i_y_offset,
229 i_width, i_height, i_alpha );
231 case VLC_FOURCC('R','V','1','6'):
232 case VLC_FOURCC('R','V','2','4'):
233 case VLC_FOURCC('R','V','3','2'):
234 BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
235 i_x_offset, i_y_offset,
236 i_width, i_height, i_alpha );
239 case VLC_FOURCC('Y','V','1','2'):
240 case VLC_FOURCC('I','4','2','0'):
241 switch( p_filter->fmt_out.video.i_chroma )
243 case VLC_FOURCC('I','4','2','0'):
244 case VLC_FOURCC('Y','V','1','2'):
245 if( i_alpha == 0xff )
246 BlendI420I420_no_alpha(
247 p_filter, p_dst, p_dst_orig, p_src,
248 i_x_offset, i_y_offset,
251 BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
252 i_x_offset, i_y_offset,
253 i_width, i_height, i_alpha );
255 case VLC_FOURCC('Y','U','Y','2'):
256 case VLC_FOURCC('U','Y','V','Y'):
257 case VLC_FOURCC('Y','V','Y','U'):
258 BlendI420YUVPacked( p_filter, p_dst, p_dst_orig, p_src,
259 i_x_offset, i_y_offset,
260 i_width, i_height, i_alpha );
262 case VLC_FOURCC('R','V','1','6'):
263 BlendI420R16( p_filter, p_dst, p_dst_orig, p_src,
264 i_x_offset, i_y_offset,
265 i_width, i_height, i_alpha );
267 case VLC_FOURCC('R','V','2','4'):
268 case VLC_FOURCC('R','V','3','2'):
269 BlendI420R24( p_filter, p_dst, p_dst_orig, p_src,
270 i_x_offset, i_y_offset,
271 i_width, i_height, i_alpha );
274 case VLC_FOURCC('R','G','B','A'):
275 switch( p_filter->fmt_out.video.i_chroma )
277 case VLC_FOURCC('I','4','2','0'):
278 case VLC_FOURCC('Y','V','1','2'):
279 BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
280 i_x_offset, i_y_offset,
281 i_width, i_height, i_alpha );
283 case VLC_FOURCC('Y','U','Y','2'):
284 case VLC_FOURCC('U','Y','V','Y'):
285 case VLC_FOURCC('Y','V','Y','U'):
286 BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
287 i_x_offset, i_y_offset,
288 i_width, i_height, i_alpha );
290 case VLC_FOURCC('R','V','2','4'):
291 case VLC_FOURCC('R','V','3','2'):
292 BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
293 i_x_offset, i_y_offset,
294 i_width, i_height, i_alpha );
296 case VLC_FOURCC('R','V','1','6'):
297 BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
298 i_x_offset, i_y_offset,
299 i_width, i_height, i_alpha );
304 msg_Dbg( p_filter, "no matching alpha blending routine "
305 "(chroma: %4.4s -> %4.4s)",
306 (char *)&p_filter->fmt_in.video.i_chroma,
307 (char *)&p_filter->fmt_out.video.i_chroma );
310 /***********************************************************************
312 ***********************************************************************/
313 static inline void yuv_to_rgb( int *r, int *g, int *b,
314 uint8_t y1, uint8_t u1, uint8_t v1 )
316 /* macros used for YUV pixel conversions */
317 # define SCALEBITS 10
318 # define ONE_HALF (1 << (SCALEBITS - 1))
319 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
320 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
322 int y, cb, cr, r_add, g_add, b_add;
326 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
327 g_add = - FIX(0.34414*255.0/224.0) * cb
328 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
329 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
330 y = (y1 - 16) * FIX(255.0/219.0);
331 *r = CLAMP((y + r_add) >> SCALEBITS);
332 *g = CLAMP((y + g_add) >> SCALEBITS);
333 *b = CLAMP((y + b_add) >> SCALEBITS);
336 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
337 int r, int g, int b )
339 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
340 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
341 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
344 /***********************************************************************
346 ***********************************************************************/
347 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
348 picture_t *p_dst_orig, picture_t *p_src,
349 int i_x_offset, int i_y_offset,
350 int i_width, int i_height, int i_alpha )
352 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
353 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
354 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
355 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
357 int i_x, i_y, i_trans = 0;
358 vlc_bool_t b_even_scanline = i_y_offset % 2;
360 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
361 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
362 p_filter->fmt_out.video.i_x_offset +
363 p_dst->p[Y_PLANE].i_pitch *
364 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
365 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
366 p_filter->fmt_out.video.i_x_offset/2 +
367 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
368 p_dst->p[U_PLANE].i_pitch;
369 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
370 p_filter->fmt_out.video.i_x_offset/2 +
371 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
372 p_dst->p[V_PLANE].i_pitch;
374 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
375 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
376 p_filter->fmt_out.video.i_x_offset +
377 p_dst_orig->p[Y_PLANE].i_pitch *
378 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
379 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
380 p_filter->fmt_out.video.i_x_offset/2 +
381 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
382 p_dst_orig->p[U_PLANE].i_pitch;
383 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
384 p_filter->fmt_out.video.i_x_offset/2 +
385 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
386 p_dst_orig->p[V_PLANE].i_pitch;
388 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
389 p_src2_y = p_src->p[Y_PLANE].p_pixels +
390 p_filter->fmt_in.video.i_x_offset +
391 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
392 p_src2_u = p_src->p[U_PLANE].p_pixels +
393 p_filter->fmt_in.video.i_x_offset/2 +
394 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
395 p_src2_v = p_src->p[V_PLANE].p_pixels +
396 p_filter->fmt_in.video.i_x_offset/2 +
397 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
399 p_trans = p_src->p[A_PLANE].p_pixels +
400 p_filter->fmt_in.video.i_x_offset +
401 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
403 #define MAX_TRANS 255
406 /* Draw until we reach the bottom of the subtitle */
407 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
408 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
409 p_src2_y += i_src2_pitch,
410 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
411 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
412 p_src2_u += i_src2_pitch,
413 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
414 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
415 p_src2_v += i_src2_pitch )
417 b_even_scanline = !b_even_scanline;
419 /* Draw until we reach the end of the line */
420 for( i_x = 0; i_x < i_width; i_x++ )
423 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
426 /* Completely transparent. Don't change pixel */
429 else if( i_trans == MAX_TRANS )
431 /* Completely opaque. Completely overwrite underlying pixel */
432 p_dst_y[i_x] = p_src2_y[i_x];
434 if( b_even_scanline && i_x % 2 == 0 )
436 p_dst_u[i_x/2] = p_src2_u[i_x];
437 p_dst_v[i_x/2] = p_src2_v[i_x];
443 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
444 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
447 if( b_even_scanline && i_x % 2 == 0 )
449 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
450 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
452 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
453 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - 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 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
491 p_src2_y = p_src->p[Y_PLANE].p_pixels +
492 p_filter->fmt_in.video.i_x_offset +
493 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
494 p_src2_u = p_src->p[U_PLANE].p_pixels +
495 p_filter->fmt_in.video.i_x_offset/2 +
496 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
497 p_src2_v = p_src->p[V_PLANE].p_pixels +
498 p_filter->fmt_in.video.i_x_offset/2 +
499 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
501 p_trans = p_src->p[A_PLANE].p_pixels +
502 p_filter->fmt_in.video.i_x_offset +
503 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
505 #define MAX_TRANS 255
508 /* Draw until we reach the bottom of the subtitle */
509 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
510 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
511 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
512 p_src2_v += i_src2_pitch )
514 /* Draw until we reach the end of the line */
515 for( i_x = 0; i_x < i_width; i_x++ )
518 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
521 /* Completely transparent. Don't change pixel */
524 else if( i_trans == MAX_TRANS )
526 /* Completely opaque. Completely overwrite underlying pixel */
527 yuv_to_rgb( &r, &g, &b,
528 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
530 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
535 /* FIXME: do the blending */
536 yuv_to_rgb( &r, &g, &b,
537 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
539 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
549 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
550 picture_t *p_dst_orig, picture_t *p_src,
551 int i_x_offset, int i_y_offset,
552 int i_width, int i_height, int i_alpha )
554 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
555 uint8_t *p_dst, *p_src1, *p_src2_y;
556 uint8_t *p_src2_u, *p_src2_v;
558 int i_x, i_y, i_pix_pitch, i_trans = 0;
561 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
562 i_dst_pitch = p_dst_pic->p->i_pitch;
563 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
564 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
565 p_dst_pic->p->i_pitch *
566 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
568 i_src1_pitch = p_dst_orig->p->i_pitch;
569 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
570 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
571 p_dst_orig->p->i_pitch *
572 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
574 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
575 p_src2_y = p_src->p[Y_PLANE].p_pixels +
576 p_filter->fmt_in.video.i_x_offset +
577 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
578 p_src2_u = p_src->p[U_PLANE].p_pixels +
579 p_filter->fmt_in.video.i_x_offset/2 +
580 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
581 p_src2_v = p_src->p[V_PLANE].p_pixels +
582 p_filter->fmt_in.video.i_x_offset/2 +
583 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
585 p_trans = p_src->p[A_PLANE].p_pixels +
586 p_filter->fmt_in.video.i_x_offset +
587 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
589 #define MAX_TRANS 255
592 if( (i_pix_pitch == 4)
593 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
597 ** if picture pixels are 32 bits long and lines addresses are 32 bit
598 ** aligned, optimize rendering
600 uint32_t *p32_dst = (uint32_t *)p_dst;
601 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
602 uint32_t *p32_src1 = (uint32_t *)p_src1;
603 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
605 int i_rshift, i_gshift, i_bshift;
606 uint32_t i_rmask, i_gmask, i_bmask;
608 if( p_dst_pic->p_heap )
610 i_rmask = p_dst_pic->p_heap->i_rmask;
611 i_gmask = p_dst_pic->p_heap->i_gmask;
612 i_bmask = p_dst_pic->p_heap->i_bmask;
613 i_rshift = p_dst_pic->p_heap->i_lrshift;
614 i_gshift = p_dst_pic->p_heap->i_lgshift;
615 i_bshift = p_dst_pic->p_heap->i_lbshift;
619 i_rmask = p_dst_pic->format.i_rmask;
620 i_gmask = p_dst_pic->format.i_gmask;
621 i_bmask = p_dst_pic->format.i_bmask;
623 if( (i_rmask == 0x00FF0000)
624 && (i_gmask == 0x0000FF00)
625 && (i_bmask == 0x000000FF) )
627 /* X8R8G8B8 pixel layout */
632 else if( (i_rmask == 0xFF000000)
633 && (i_gmask == 0x00FF0000)
634 && (i_bmask == 0x0000FF00) )
636 /* R8G8B8X8 pixel layout */
646 /* Draw until we reach the bottom of the subtitle */
647 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
648 p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
649 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
650 p_src2_v += i_src2_pitch )
652 /* Draw until we reach the end of the line */
653 for( i_x = 0; i_x < i_width; i_x++ )
656 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
659 /* Completely transparent. Don't change pixel */
662 else if( i_trans == MAX_TRANS )
664 /* Completely opaque. Completely overwrite underlying pixel */
665 yuv_to_rgb( &r, &g, &b,
666 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
668 p32_dst[i_x] = (r<<i_rshift)
675 uint32_t i_pix_src1 = p32_src1[i_x];
676 yuv_to_rgb( &r, &g, &b,
677 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
679 p32_dst[i_x] = ( ( r * i_trans +
680 (uint16_t)((i_pix_src1 & i_rmask)>>i_rshift) *
681 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_rshift
683 (uint16_t)((i_pix_src1 & i_gmask)>>i_gshift) *
684 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_gshift
686 (uint16_t)((i_pix_src1 & i_bmask)>>i_bshift) *
687 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_bshift;
694 int i_rindex, i_bindex, i_gindex;
695 uint32_t i_rmask, i_gmask, i_bmask;
699 i_rmask = p_dst_pic->format.i_rmask;
700 i_gmask = p_dst_pic->format.i_gmask;
701 i_bmask = p_dst_pic->format.i_bmask;
704 ** quick and dirty way to get byte index from mask
705 ** will only work correctly if mask are 8 bit aligned
706 ** and are 8 bit long
708 #ifdef WORDS_BIGENDIAN
709 i_rindex = ((i_rmask>>16) & 1)
712 i_gindex = ((i_gmask>>16) & 1)
715 i_bindex = ((i_bmask>>16) & 1)
719 i_rindex = ((i_rmask>>24) & 3)
720 | ((i_rmask>>16) & 2)
721 | ((i_rmask>>8) & 1);
722 i_gindex = ((i_gmask>>24) & 3)
723 | ((i_gmask>>16) & 2)
724 | ((i_gmask>>8) & 1);
725 i_bindex = ((i_bmask>>24) & 3)
726 | ((i_bmask>>16) & 2)
727 | ((i_bmask>>8) & 1);
730 /* Draw until we reach the bottom of the subtitle */
731 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
732 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
733 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
734 p_src2_v += i_src2_pitch )
736 /* Draw until we reach the end of the line */
737 for( i_x = 0; i_x < i_width; i_x++ )
740 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
743 /* Completely transparent. Don't change pixel */
748 int i_pos = i_x * i_pix_pitch;
749 if( i_trans == MAX_TRANS )
752 /* Completely opaque. Completely overwrite underlying pixel */
753 yuv_to_rgb( &r, &g, &b,
754 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
756 p_dst[i_pos + i_rindex ] = r;
757 p_dst[i_pos + i_gindex ] = g;
758 p_dst[i_pos + i_bindex ] = b;
762 int i_rpos = i_pos + i_rindex;
763 int i_gpos = i_pos + i_gindex;
764 int i_bpos = i_pos + i_bindex;
767 yuv_to_rgb( &r, &g, &b,
768 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
770 p_dst[i_rpos] = ( r * i_trans +
771 (uint16_t)p_src1[i_rpos] *
772 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
773 p_dst[i_gpos] = ( r * i_trans +
774 (uint16_t)p_src1[i_gpos] *
775 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
776 p_dst[i_bpos] = ( r * i_trans +
777 (uint16_t)p_src1[i_gpos] *
778 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
791 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
792 picture_t *p_dst_orig, picture_t *p_src,
793 int i_x_offset, int i_y_offset,
794 int i_width, int i_height, int i_alpha )
796 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
797 uint8_t *p_dst, *p_src1, *p_src2_y;
798 uint8_t *p_src2_u, *p_src2_v;
800 int i_x, i_y, i_pix_pitch, i_trans = 0;
801 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
802 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
804 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
810 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
816 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
824 i_dst_pitch = p_dst_pic->p->i_pitch;
825 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
826 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
827 p_dst_pic->p->i_pitch *
828 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
830 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
831 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
832 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
833 p_dst_orig->p->i_pitch *
834 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
836 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
837 p_src2_y = p_src->p[Y_PLANE].p_pixels +
838 p_filter->fmt_in.video.i_x_offset +
839 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
840 p_src2_u = p_src->p[U_PLANE].p_pixels +
841 p_filter->fmt_in.video.i_x_offset/2 +
842 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
843 p_src2_v = p_src->p[V_PLANE].p_pixels +
844 p_filter->fmt_in.video.i_x_offset/2 +
845 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
847 p_trans = p_src->p[A_PLANE].p_pixels +
848 p_filter->fmt_in.video.i_x_offset +
849 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
851 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
853 #define MAX_TRANS 255
856 /* Draw until we reach the bottom of the subtitle */
857 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
858 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
859 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
860 p_src2_v += i_src2_pitch )
862 /* Draw until we reach the end of the line */
863 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
865 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
868 /* Completely transparent. Don't change pixel */
870 else if( i_trans == MAX_TRANS )
872 /* Completely opaque. Completely overwrite underlying pixel */
873 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
877 if( p_trans[i_x+1] > 0xaa )
879 p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
880 p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
884 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
885 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
892 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_trans +
893 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
900 if( p_trans[i_x+1] > 0xaa )
902 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
903 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
910 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
911 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
913 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
914 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
926 /***********************************************************************
928 ***********************************************************************/
929 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
930 picture_t *p_dst_orig, picture_t *p_src,
931 int i_x_offset, int i_y_offset,
932 int i_width, int i_height, int i_alpha )
934 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
935 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
936 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
937 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
939 vlc_bool_t b_even_scanline = i_y_offset % 2;
941 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
942 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
943 p_filter->fmt_out.video.i_x_offset +
944 p_dst->p[Y_PLANE].i_pitch *
945 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
946 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
947 p_filter->fmt_out.video.i_x_offset/2 +
948 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
949 p_dst->p[U_PLANE].i_pitch;
950 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
951 p_filter->fmt_out.video.i_x_offset/2 +
952 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
953 p_dst->p[V_PLANE].i_pitch;
955 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
956 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
957 p_filter->fmt_out.video.i_x_offset +
958 p_dst_orig->p[Y_PLANE].i_pitch *
959 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
960 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
961 p_filter->fmt_out.video.i_x_offset/2 +
962 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
963 p_dst_orig->p[U_PLANE].i_pitch;
964 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
965 p_filter->fmt_out.video.i_x_offset/2 +
966 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
967 p_dst_orig->p[V_PLANE].i_pitch;
969 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
970 p_src2_y = p_src->p[Y_PLANE].p_pixels +
971 p_filter->fmt_in.video.i_x_offset +
972 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
973 p_src2_u = p_src->p[U_PLANE].p_pixels +
974 p_filter->fmt_in.video.i_x_offset/2 +
975 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
976 p_src2_v = p_src->p[V_PLANE].p_pixels +
977 p_filter->fmt_in.video.i_x_offset/2 +
978 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
980 #define MAX_TRANS 255
983 /* Draw until we reach the bottom of the subtitle */
984 for( i_y = 0; i_y < i_height; i_y++,
985 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
986 p_src2_y += i_src2_pitch )
988 if( b_even_scanline )
990 p_dst_u += i_dst_pitch/2;
991 p_dst_v += i_dst_pitch/2;
992 p_src1_u += i_src1_pitch/2;
993 p_src1_v += i_src1_pitch/2;
995 b_even_scanline = !b_even_scanline;
997 /* Draw until we reach the end of the line */
998 for( i_x = 0; i_x < i_width; i_x++ )
1000 if( i_alpha == MAX_TRANS )
1002 /* Completely opaque. Completely overwrite underlying pixel */
1003 p_dst_y[i_x] = p_src2_y[i_x];
1005 if( b_even_scanline && i_x % 2 == 0 )
1007 p_dst_u[i_x/2] = p_src2_u[i_x/2];
1008 p_dst_v[i_x/2] = p_src2_v[i_x/2];
1014 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1015 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_alpha) )
1018 if( b_even_scanline && i_x % 2 == 0 )
1020 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x/2] * i_alpha +
1021 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_alpha) )
1023 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x/2] * i_alpha +
1024 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_alpha) )
1030 p_src2_u += i_src2_pitch/2;
1031 p_src2_v += i_src2_pitch/2;
1040 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
1041 picture_t *p_dst_orig, picture_t *p_src,
1042 int i_x_offset, int i_y_offset,
1043 int i_width, int i_height )
1045 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1046 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
1047 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
1048 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
1050 vlc_bool_t b_even_scanline = i_y_offset % 2;
1052 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1053 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1054 p_filter->fmt_out.video.i_x_offset +
1055 p_dst->p[Y_PLANE].i_pitch *
1056 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1057 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1058 p_filter->fmt_out.video.i_x_offset/2 +
1059 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1060 p_dst->p[U_PLANE].i_pitch;
1061 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1062 p_filter->fmt_out.video.i_x_offset/2 +
1063 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1064 p_dst->p[V_PLANE].i_pitch;
1066 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1067 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1068 p_filter->fmt_out.video.i_x_offset +
1069 p_dst_orig->p[Y_PLANE].i_pitch *
1070 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1071 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1072 p_filter->fmt_out.video.i_x_offset/2 +
1073 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1074 p_dst_orig->p[U_PLANE].i_pitch;
1075 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1076 p_filter->fmt_out.video.i_x_offset/2 +
1077 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1078 p_dst_orig->p[V_PLANE].i_pitch;
1080 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1081 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1082 p_filter->fmt_in.video.i_x_offset +
1083 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1084 p_src2_u = p_src->p[U_PLANE].p_pixels +
1085 p_filter->fmt_in.video.i_x_offset/2 +
1086 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1087 p_src2_v = p_src->p[V_PLANE].p_pixels +
1088 p_filter->fmt_in.video.i_x_offset/2 +
1089 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1093 /* Draw until we reach the bottom of the subtitle */
1094 for( i_y = 0; i_y < i_height; i_y++,
1095 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1096 p_src2_y += i_src2_pitch )
1098 /* Completely opaque. Completely overwrite underlying pixel */
1099 p_filter->p_libvlc->pf_memcpy( p_dst_y, p_src2_y, i_width );
1100 if( b_even_scanline )
1102 p_dst_u += i_dst_pitch/2;
1103 p_dst_v += i_dst_pitch/2;
1104 p_src1_u += i_src1_pitch/2;
1105 p_src1_v += i_src1_pitch/2;
1109 p_filter->p_libvlc->pf_memcpy( p_dst_u, p_src2_u, i_width/2 );
1110 p_filter->p_libvlc->pf_memcpy( p_dst_v, p_src2_v, i_width/2 );
1112 b_even_scanline = !b_even_scanline;
1115 p_src2_u += i_src2_pitch/2;
1116 p_src2_v += i_src2_pitch/2;
1123 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1124 picture_t *p_dst_orig, picture_t *p_src,
1125 int i_x_offset, int i_y_offset,
1126 int i_width, int i_height, int i_alpha )
1128 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1129 uint8_t *p_dst, *p_src1, *p_src2_y;
1130 uint8_t *p_src2_u, *p_src2_v;
1131 int i_x, i_y, i_pix_pitch;
1134 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1135 i_dst_pitch = p_dst_pic->p->i_pitch;
1136 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1137 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1138 p_dst_pic->p->i_pitch *
1139 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1141 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1142 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1143 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1144 p_dst_orig->p->i_pitch *
1145 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1147 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1148 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1149 p_filter->fmt_in.video.i_x_offset +
1150 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1151 p_src2_u = p_src->p[U_PLANE].p_pixels +
1152 p_filter->fmt_in.video.i_x_offset/2 +
1153 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1154 p_src2_v = p_src->p[V_PLANE].p_pixels +
1155 p_filter->fmt_in.video.i_x_offset/2 +
1156 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1158 #define MAX_TRANS 255
1159 #define TRANS_BITS 8
1161 /* Draw until we reach the bottom of the subtitle */
1162 for( i_y = 0; i_y < i_height; i_y++,
1163 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1164 p_src2_y += i_src2_pitch )
1166 /* Draw until we reach the end of the line */
1167 for( i_x = 0; i_x < i_width; i_x++ )
1169 if( i_alpha == MAX_TRANS )
1171 /* Completely opaque. Completely overwrite underlying pixel */
1172 yuv_to_rgb( &r, &g, &b,
1173 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1175 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1180 /* FIXME: do the blending */
1181 yuv_to_rgb( &r, &g, &b,
1182 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1184 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1188 p_src2_u += i_src2_pitch/2;
1189 p_src2_v += i_src2_pitch/2;
1199 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1200 picture_t *p_dst_orig, picture_t *p_src,
1201 int i_x_offset, int i_y_offset,
1202 int i_width, int i_height, int i_alpha )
1204 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1205 uint8_t *p_dst, *p_src1, *p_src2_y;
1206 uint8_t *p_src2_u, *p_src2_v;
1207 int i_x, i_y, i_pix_pitch;
1210 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1211 i_dst_pitch = p_dst_pic->p->i_pitch;
1212 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1213 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1214 p_dst_pic->p->i_pitch *
1215 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1217 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1218 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1219 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1220 p_dst_orig->p->i_pitch *
1221 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1223 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1224 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1225 p_filter->fmt_in.video.i_x_offset +
1226 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1227 p_src2_u = p_src->p[U_PLANE].p_pixels +
1228 p_filter->fmt_in.video.i_x_offset/2 +
1229 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1230 p_src2_v = p_src->p[V_PLANE].p_pixels +
1231 p_filter->fmt_in.video.i_x_offset/2 +
1232 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1234 #define MAX_TRANS 255
1235 #define TRANS_BITS 8
1237 /* Draw until we reach the bottom of the subtitle */
1238 for( i_y = 0; i_y < i_height; i_y++,
1239 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1240 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1241 p_src2_v += i_src2_pitch )
1243 /* Draw until we reach the end of the line */
1244 for( i_x = 0; i_x < i_width; i_x++ )
1246 if( i_alpha == MAX_TRANS )
1248 /* Completely opaque. Completely overwrite underlying pixel */
1249 yuv_to_rgb( &r, &g, &b,
1250 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1252 p_dst[i_x * i_pix_pitch] = r;
1253 p_dst[i_x * i_pix_pitch + 1] = g;
1254 p_dst[i_x * i_pix_pitch + 2] = b;
1259 yuv_to_rgb( &r, &g, &b,
1260 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1262 p_dst[i_x * i_pix_pitch] = ( r * i_alpha +
1263 (uint16_t)p_src1[i_x * i_pix_pitch] *
1264 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1265 p_dst[i_x * i_pix_pitch + 1] = ( g * i_alpha +
1266 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1267 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1268 p_dst[i_x * i_pix_pitch + 2] = ( b * i_alpha +
1269 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1270 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1274 p_src2_u += i_src2_pitch/2;
1275 p_src2_v += i_src2_pitch/2;
1285 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1286 picture_t *p_dst_orig, picture_t *p_src,
1287 int i_x_offset, int i_y_offset,
1288 int i_width, int i_height, int i_alpha )
1290 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1291 uint8_t *p_dst, *p_src1, *p_src2_y;
1292 uint8_t *p_src2_u, *p_src2_v;
1293 int i_x, i_y, i_pix_pitch;
1294 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1295 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1297 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1303 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1309 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1317 i_dst_pitch = p_dst_pic->p->i_pitch;
1318 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1319 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1320 p_dst_pic->p->i_pitch *
1321 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1323 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1324 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1325 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1326 p_dst_orig->p->i_pitch *
1327 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1329 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1330 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1331 p_filter->fmt_in.video.i_x_offset +
1332 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1333 p_src2_u = p_src->p[U_PLANE].p_pixels +
1334 p_filter->fmt_in.video.i_x_offset/2 +
1335 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1336 p_src2_v = p_src->p[V_PLANE].p_pixels +
1337 p_filter->fmt_in.video.i_x_offset/2 +
1338 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1340 i_width &= ~1; /* Needs to be a multiple of 2 */
1342 #define MAX_TRANS 255
1343 #define TRANS_BITS 8
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_src1 += i_src1_pitch,
1348 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1349 p_src2_v += i_src2_pitch )
1351 /* Draw until we reach the end of the line */
1352 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1354 if( i_alpha == MAX_TRANS )
1356 /* Completely opaque. Completely overwrite underlying pixel */
1357 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
1361 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x/2];
1362 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x/2];
1368 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1369 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_alpha) )
1374 uint16_t i_u = p_src2_u[i_x/2];
1375 uint16_t i_v = p_src2_v[i_x/2];
1376 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_alpha +
1377 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_alpha) )
1379 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_alpha +
1380 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_alpha) )
1387 p_src2_u += i_src2_pitch/2;
1388 p_src2_v += i_src2_pitch/2;
1398 /***********************************************************************
1400 ***********************************************************************/
1401 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1402 picture_t *p_dst_orig, picture_t *p_src,
1403 int i_x_offset, int i_y_offset,
1404 int i_width, int i_height, int i_alpha )
1406 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1407 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1408 uint8_t *p_src1_u, *p_dst_u;
1409 uint8_t *p_src1_v, *p_dst_v;
1410 int i_x, i_y, i_trans;
1411 vlc_bool_t b_even_scanline = i_y_offset % 2;
1413 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1414 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1415 p_filter->fmt_out.video.i_x_offset +
1416 p_dst->p[Y_PLANE].i_pitch *
1417 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1418 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1419 p_filter->fmt_out.video.i_x_offset/2 +
1420 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1421 p_dst->p[U_PLANE].i_pitch;
1422 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1423 p_filter->fmt_out.video.i_x_offset/2 +
1424 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1425 p_dst->p[V_PLANE].i_pitch;
1427 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1428 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1429 p_filter->fmt_out.video.i_x_offset +
1430 p_dst_orig->p[Y_PLANE].i_pitch *
1431 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1432 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1433 p_filter->fmt_out.video.i_x_offset/2 +
1434 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1435 p_dst_orig->p[U_PLANE].i_pitch;
1436 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1437 p_filter->fmt_out.video.i_x_offset/2 +
1438 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1439 p_dst_orig->p[V_PLANE].i_pitch;
1441 i_src2_pitch = p_src->p->i_pitch;
1442 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1443 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1445 #define MAX_TRANS 255
1446 #define TRANS_BITS 8
1447 #define p_trans p_src2
1448 #define p_pal p_filter->fmt_in.video.p_palette->palette
1450 /* Draw until we reach the bottom of the subtitle */
1451 for( i_y = 0; i_y < i_height; i_y++,
1452 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1453 p_src2 += i_src2_pitch,
1454 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1455 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1456 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1457 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1459 b_even_scanline = !b_even_scanline;
1461 /* Draw until we reach the end of the line */
1462 for( i_x = 0; i_x < i_width; i_x++ )
1464 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1467 /* Completely transparent. Don't change pixel */
1470 else if( i_trans == MAX_TRANS )
1472 /* Completely opaque. Completely overwrite underlying pixel */
1473 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
1475 if( b_even_scanline && ((i_x % 2) == 0) )
1477 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
1478 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
1484 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
1485 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1488 if( b_even_scanline && ((i_x % 2) == 0) )
1490 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
1491 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1493 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
1494 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1508 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1509 picture_t *p_dst_orig, picture_t *p_src,
1510 int i_x_offset, int i_y_offset,
1511 int i_width, int i_height, int i_alpha )
1513 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1514 uint8_t *p_src1, *p_src2, *p_dst;
1515 int i_x, i_y, i_pix_pitch, i_trans;
1516 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1517 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1519 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1525 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1531 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1539 i_dst_pitch = p_dst_pic->p->i_pitch;
1540 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1541 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1542 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1544 i_src1_pitch = p_dst_orig->p->i_pitch;
1545 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1546 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1547 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1549 i_src2_pitch = p_src->p->i_pitch;
1550 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1551 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1553 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1555 #define MAX_TRANS 255
1556 #define TRANS_BITS 8
1557 #define p_trans p_src2
1558 #define p_pal p_filter->fmt_in.video.p_palette->palette
1560 /* Draw until we reach the bottom of the subtitle */
1561 for( i_y = 0; i_y < i_height; i_y++,
1562 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1564 /* Draw until we reach the end of the line */
1565 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1567 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1570 /* Completely transparent. Don't change pixel */
1572 else if( i_trans == MAX_TRANS )
1574 /* Completely opaque. Completely overwrite underlying pixel */
1575 p_dst[i_x * 2 + i_l_offset] = p_pal[p_src2[i_x]][0];
1579 if( p_trans[i_x+1] > 0xaa )
1581 p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1582 p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1586 p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1587 p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1594 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1595 i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1596 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1602 if( p_trans[i_x+1] > 0xaa )
1604 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1605 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1609 i_u = p_pal[p_src2[i_x]][1];
1610 i_v = p_pal[p_src2[i_x]][2];
1613 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1614 i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1615 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1616 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1617 i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1618 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1632 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1633 picture_t *p_dst_orig, picture_t *p_src,
1634 int i_x_offset, int i_y_offset,
1635 int i_width, int i_height, int i_alpha )
1637 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1638 uint8_t *p_src1, *p_src2, *p_dst;
1639 int i_x, i_y, i_pix_pitch, i_trans;
1641 video_palette_t rgbpalette;
1643 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1644 i_dst_pitch = p_dst_pic->p->i_pitch;
1645 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1646 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1647 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1649 i_src1_pitch = p_dst_orig->p->i_pitch;
1650 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1651 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1652 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1654 i_src2_pitch = p_src->p->i_pitch;
1655 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1656 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1658 #define MAX_TRANS 255
1659 #define TRANS_BITS 8
1660 #define p_trans p_src2
1661 #define p_pal p_filter->fmt_in.video.p_palette->palette
1662 #define rgbpal rgbpalette.palette
1664 /* Convert palette first */
1665 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1668 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1670 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1672 *(uint16_t *)rgbpal[i_y] =
1673 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1677 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1681 /* Draw until we reach the bottom of the subtitle */
1682 for( i_y = 0; i_y < i_height; i_y++,
1683 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1685 /* Draw until we reach the end of the line */
1686 for( i_x = 0; i_x < i_width; i_x++ )
1688 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1691 /* Completely transparent. Don't change pixel */
1694 else if( i_trans == MAX_TRANS ||
1695 p_filter->fmt_out.video.i_chroma ==
1696 VLC_FOURCC('R','V','1','6') )
1698 /* Completely opaque. Completely overwrite underlying pixel */
1699 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1700 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1701 if( p_filter->fmt_out.video.i_chroma !=
1702 VLC_FOURCC('R','V','1','6') )
1703 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1708 p_dst[i_x * i_pix_pitch] = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1709 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1710 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1711 p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1712 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1713 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1714 p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1715 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1716 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1729 /***********************************************************************
1731 ***********************************************************************/
1732 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1733 picture_t *p_dst_orig, picture_t *p_src,
1734 int i_x_offset, int i_y_offset,
1735 int i_width, int i_height, int i_alpha )
1737 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1738 uint8_t *p_src1_y, *p_dst_y;
1739 uint8_t *p_src1_u, *p_dst_u;
1740 uint8_t *p_src1_v, *p_dst_v;
1742 int i_x, i_y, i_trans;
1745 vlc_bool_t b_even_scanline = i_y_offset % 2;
1747 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1748 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1749 p_filter->fmt_out.video.i_x_offset +
1750 p_dst->p[Y_PLANE].i_pitch *
1751 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1752 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1753 p_filter->fmt_out.video.i_x_offset/2 +
1754 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1755 p_dst->p[U_PLANE].i_pitch;
1756 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1757 p_filter->fmt_out.video.i_x_offset/2 +
1758 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1759 p_dst->p[V_PLANE].i_pitch;
1761 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1762 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1763 p_filter->fmt_out.video.i_x_offset +
1764 p_dst_orig->p[Y_PLANE].i_pitch *
1765 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1766 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1767 p_filter->fmt_out.video.i_x_offset/2 +
1768 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1769 p_dst_orig->p[U_PLANE].i_pitch;
1770 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1771 p_filter->fmt_out.video.i_x_offset/2 +
1772 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1773 p_dst_orig->p[V_PLANE].i_pitch;
1775 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1776 i_src2_pitch = p_src->p->i_pitch;
1777 p_src2 = p_src->p->p_pixels +
1778 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1779 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1782 #define MAX_TRANS 255
1783 #define TRANS_BITS 8
1785 /* Draw until we reach the bottom of the subtitle */
1786 for( i_y = 0; i_y < i_height; i_y++,
1787 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1788 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1789 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1790 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1791 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1792 p_src2 += i_src2_pitch )
1794 b_even_scanline = !b_even_scanline;
1796 /* Draw until we reach the end of the line */
1797 for( i_x = 0; i_x < i_width; i_x++ )
1799 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1800 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1801 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1802 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1805 /* Completely transparent. Don't change pixel */
1808 else if( i_trans == MAX_TRANS )
1810 /* Completely opaque. Completely overwrite underlying pixel */
1811 rgb_to_yuv( &y, &u, &v, R, G, B );
1814 if( b_even_scanline && i_x % 2 == 0 )
1823 rgb_to_yuv( &y, &u, &v, R, G, B );
1824 p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1825 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1828 if( b_even_scanline && i_x % 2 == 0 )
1830 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1831 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1833 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1834 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1849 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1850 picture_t *p_dst_orig, picture_t *p_src,
1851 int i_x_offset, int i_y_offset,
1852 int i_width, int i_height, int i_alpha )
1854 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1855 uint8_t *p_dst, *p_src1, *p_src2;
1856 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1858 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1859 i_dst_pitch = p_dst_pic->p->i_pitch;
1860 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1861 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1862 p_dst_pic->p->i_pitch *
1863 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1865 i_src1_pitch = p_dst_orig->p->i_pitch;
1866 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1867 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1868 p_dst_orig->p->i_pitch *
1869 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1871 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1872 i_src2_pitch = p_src->p->i_pitch;
1873 p_src2 = p_src->p->p_pixels +
1874 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1875 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1877 #define MAX_TRANS 255
1878 #define TRANS_BITS 8
1880 /* Draw until we reach the bottom of the subtitle */
1881 for( i_y = 0; i_y < i_height; i_y++,
1882 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1884 /* Draw until we reach the end of the line */
1885 for( i_x = 0; i_x < i_width; i_x++ )
1887 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1888 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1889 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1890 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1893 /* Completely transparent. Don't change pixel */
1896 else if( i_trans == MAX_TRANS )
1898 /* Completely opaque. Completely overwrite underlying pixel */
1899 p_dst[i_x * i_pix_pitch + 0] = R;
1900 p_dst[i_x * i_pix_pitch + 1] = G;
1901 p_dst[i_x * i_pix_pitch + 2] = B;
1906 p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1907 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1908 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1909 p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1910 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1911 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1912 p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1913 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1914 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1927 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1928 picture_t *p_dst_orig, picture_t *p_src,
1929 int i_x_offset, int i_y_offset,
1930 int i_width, int i_height, int i_alpha )
1932 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1933 uint8_t *p_dst, *p_src1, *p_src2;
1934 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1937 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1938 i_dst_pitch = p_dst_pic->p->i_pitch;
1939 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1940 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1941 p_dst_pic->p->i_pitch *
1942 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1944 i_src1_pitch = p_dst_orig->p->i_pitch;
1945 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1946 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1947 p_dst_orig->p->i_pitch *
1948 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1950 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1951 i_src2_pitch = p_src->p->i_pitch;
1952 p_src2 = p_src->p->p_pixels +
1953 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1954 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1956 #define MAX_TRANS 255
1957 #define TRANS_BITS 8
1959 /* Draw until we reach the bottom of the subtitle */
1960 for( i_y = 0; i_y < i_height; i_y++,
1961 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1963 /* Draw until we reach the end of the line */
1964 for( i_x = 0; i_x < i_width; i_x++ )
1966 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1967 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1968 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1969 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1972 /* Completely transparent. Don't change pixel */
1975 else if( i_trans == MAX_TRANS )
1977 /* Completely opaque. Completely overwrite underlying pixel */
1978 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1983 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1984 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1985 ( ( ( (R >> 3)*i_trans
1986 + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1987 >> TRANS_BITS ) << 11 )
1988 | ( ( ( (G >> 2)*i_trans
1989 + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1990 >> TRANS_BITS ) << 5 )
1991 | ( ( ( (B >> 3)*i_trans
1992 + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
2006 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
2007 picture_t *p_dst_orig, picture_t *p_src,
2008 int i_x_offset, int i_y_offset,
2009 int i_width, int i_height, int i_alpha )
2011 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
2012 uint8_t *p_dst, *p_src1, *p_src2;
2014 int i_x, i_y, i_pix_pitch, i_trans;
2015 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
2016 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
2019 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
2025 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
2031 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
2039 i_dst_pitch = p_dst_pic->p->i_pitch;
2040 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
2041 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2042 p_dst_pic->p->i_pitch *
2043 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2045 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
2046 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
2047 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2048 p_dst_orig->p->i_pitch *
2049 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2051 i_src_pix_pitch = p_src->p->i_pixel_pitch;
2052 i_src2_pitch = p_src->p->i_pitch;
2053 p_src2 = p_src->p->p_pixels +
2054 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
2055 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
2057 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
2059 #define MAX_TRANS 255
2060 #define TRANS_BITS 8
2062 /* Draw until we reach the bottom of the subtitle */
2063 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
2064 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
2065 p_src2 += i_src2_pitch )
2067 /* Draw until we reach the end of the line */
2068 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
2070 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
2071 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
2072 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
2073 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
2076 /* Completely transparent. Don't change pixel */
2078 else if( i_trans == MAX_TRANS )
2080 /* Completely opaque. Completely overwrite underlying pixel */
2081 rgb_to_yuv( &y, &u, &v, R, G, B );
2082 p_dst[i_x * 2 + i_l_offset] = y;
2086 p_dst[i_x * 2 + i_u_offset] = u;
2087 p_dst[i_x * 2 + i_v_offset] = v;
2093 rgb_to_yuv( &y, &u, &v, R, G, B );
2094 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)y * i_trans +
2095 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
2100 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
2101 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
2103 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
2104 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )