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 );
148 /*****************************************************************************
149 * CloseFilter: clean up the filter
150 *****************************************************************************/
151 static void CloseFilter( vlc_object_t *p_this )
153 filter_t *p_filter = (filter_t*)p_this;
154 filter_sys_t *p_sys = p_filter->p_sys;
159 /****************************************************************************
160 * Blend: the whole thing
161 ****************************************************************************
162 * This function is called just after the thread is launched.
163 ****************************************************************************/
164 static void Blend( filter_t *p_filter, picture_t *p_dst,
165 picture_t *p_dst_orig, picture_t *p_src,
166 int i_x_offset, int i_y_offset, int i_alpha )
168 int i_width, i_height;
170 if( i_alpha == 0 ) return;
172 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
173 (int)p_filter->fmt_in.video.i_visible_width);
175 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
176 (int)p_filter->fmt_in.video.i_visible_height);
178 if( i_width <= 0 || i_height <= 0 ) return;
181 printf( "chroma: %4.4s -> %4.4s\n",
182 (char *)&p_filter->fmt_in.video.i_chroma,
183 (char *)&p_filter->fmt_out.video.i_chroma );
186 switch( p_filter->fmt_in.video.i_chroma )
188 case VLC_FOURCC('Y','U','V','A'):
189 switch( p_filter->fmt_out.video.i_chroma )
191 case VLC_FOURCC('I','4','2','0'):
192 case VLC_FOURCC('Y','V','1','2'):
193 BlendI420( p_filter, p_dst, p_dst_orig, p_src,
194 i_x_offset, i_y_offset,
195 i_width, i_height, i_alpha );
197 case VLC_FOURCC('Y','U','Y','2'):
198 case VLC_FOURCC('U','Y','V','Y'):
199 case VLC_FOURCC('Y','V','Y','U'):
200 BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
201 i_x_offset, i_y_offset,
202 i_width, i_height, i_alpha );
204 case VLC_FOURCC('R','V','1','6'):
205 BlendR16( p_filter, p_dst, p_dst_orig, p_src,
206 i_x_offset, i_y_offset,
207 i_width, i_height, i_alpha );
209 case VLC_FOURCC('R','V','2','4'):
210 case VLC_FOURCC('R','V','3','2'):
211 BlendR24( p_filter, p_dst, p_dst_orig, p_src,
212 i_x_offset, i_y_offset,
213 i_width, i_height, i_alpha );
216 case VLC_FOURCC('Y','U','V','P'):
217 switch( p_filter->fmt_out.video.i_chroma )
219 case VLC_FOURCC('I','4','2','0'):
220 case VLC_FOURCC('Y','V','1','2'):
221 BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
222 i_x_offset, i_y_offset,
223 i_width, i_height, i_alpha );
225 case VLC_FOURCC('Y','U','Y','2'):
226 case VLC_FOURCC('U','Y','V','Y'):
227 case VLC_FOURCC('Y','V','Y','U'):
228 BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
229 i_x_offset, i_y_offset,
230 i_width, i_height, i_alpha );
232 case VLC_FOURCC('R','V','1','6'):
233 case VLC_FOURCC('R','V','2','4'):
234 case VLC_FOURCC('R','V','3','2'):
235 BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
236 i_x_offset, i_y_offset,
237 i_width, i_height, i_alpha );
240 case VLC_FOURCC('Y','V','1','2'):
241 case VLC_FOURCC('I','4','2','0'):
242 switch( p_filter->fmt_out.video.i_chroma )
244 case VLC_FOURCC('I','4','2','0'):
245 case VLC_FOURCC('Y','V','1','2'):
246 if( i_alpha == 0xff )
247 BlendI420I420_no_alpha(
248 p_filter, p_dst, p_dst_orig, p_src,
249 i_x_offset, i_y_offset,
252 BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
253 i_x_offset, i_y_offset,
254 i_width, i_height, i_alpha );
256 case VLC_FOURCC('Y','U','Y','2'):
257 case VLC_FOURCC('U','Y','V','Y'):
258 case VLC_FOURCC('Y','V','Y','U'):
259 BlendI420YUVPacked( p_filter, p_dst, p_dst_orig, p_src,
260 i_x_offset, i_y_offset,
261 i_width, i_height, i_alpha );
263 case VLC_FOURCC('R','V','1','6'):
264 BlendI420R16( p_filter, p_dst, p_dst_orig, p_src,
265 i_x_offset, i_y_offset,
266 i_width, i_height, i_alpha );
268 case VLC_FOURCC('R','V','2','4'):
269 case VLC_FOURCC('R','V','3','2'):
270 BlendI420R24( p_filter, p_dst, p_dst_orig, p_src,
271 i_x_offset, i_y_offset,
272 i_width, i_height, i_alpha );
275 case VLC_FOURCC('R','G','B','A'):
276 switch( p_filter->fmt_out.video.i_chroma )
278 case VLC_FOURCC('I','4','2','0'):
279 case VLC_FOURCC('Y','V','1','2'):
280 BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
281 i_x_offset, i_y_offset,
282 i_width, i_height, i_alpha );
284 case VLC_FOURCC('Y','U','Y','2'):
285 case VLC_FOURCC('U','Y','V','Y'):
286 case VLC_FOURCC('Y','V','Y','U'):
287 BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
288 i_x_offset, i_y_offset,
289 i_width, i_height, i_alpha );
291 case VLC_FOURCC('R','V','2','4'):
292 case VLC_FOURCC('R','V','3','2'):
293 BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
294 i_x_offset, i_y_offset,
295 i_width, i_height, i_alpha );
297 case VLC_FOURCC('R','V','1','6'):
298 BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
299 i_x_offset, i_y_offset,
300 i_width, i_height, i_alpha );
305 msg_Dbg( p_filter, "no matching alpha blending routine "
306 "(chroma: %4.4s -> %4.4s)",
307 (char *)&p_filter->fmt_in.video.i_chroma,
308 (char *)&p_filter->fmt_out.video.i_chroma );
311 /***********************************************************************
313 ***********************************************************************/
314 static inline void yuv_to_rgb( int *r, int *g, int *b,
315 uint8_t y1, uint8_t u1, uint8_t v1 )
317 /* macros used for YUV pixel conversions */
318 # define SCALEBITS 10
319 # define ONE_HALF (1 << (SCALEBITS - 1))
320 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
321 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
323 int y, cb, cr, r_add, g_add, b_add;
327 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
328 g_add = - FIX(0.34414*255.0/224.0) * cb
329 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
330 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
331 y = (y1 - 16) * FIX(255.0/219.0);
332 *r = CLAMP((y + r_add) >> SCALEBITS);
333 *g = CLAMP((y + g_add) >> SCALEBITS);
334 *b = CLAMP((y + b_add) >> SCALEBITS);
337 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
338 int r, int g, int b )
340 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
341 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
342 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
345 /***********************************************************************
347 ***********************************************************************/
348 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
349 picture_t *p_dst_orig, picture_t *p_src,
350 int i_x_offset, int i_y_offset,
351 int i_width, int i_height, int i_alpha )
353 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
354 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
355 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
356 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
358 int i_x, i_y, i_trans = 0;
359 vlc_bool_t b_even_scanline = i_y_offset % 2;
361 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
362 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
363 p_filter->fmt_out.video.i_x_offset +
364 p_dst->p[Y_PLANE].i_pitch *
365 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
366 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
367 p_filter->fmt_out.video.i_x_offset/2 +
368 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
369 p_dst->p[U_PLANE].i_pitch;
370 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
371 p_filter->fmt_out.video.i_x_offset/2 +
372 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
373 p_dst->p[V_PLANE].i_pitch;
375 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
376 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
377 p_filter->fmt_out.video.i_x_offset +
378 p_dst_orig->p[Y_PLANE].i_pitch *
379 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
380 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
381 p_filter->fmt_out.video.i_x_offset/2 +
382 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
383 p_dst_orig->p[U_PLANE].i_pitch;
384 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
385 p_filter->fmt_out.video.i_x_offset/2 +
386 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
387 p_dst_orig->p[V_PLANE].i_pitch;
389 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
390 p_src2_y = p_src->p[Y_PLANE].p_pixels +
391 p_filter->fmt_in.video.i_x_offset +
392 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
393 p_src2_u = p_src->p[U_PLANE].p_pixels +
394 p_filter->fmt_in.video.i_x_offset/2 +
395 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
396 p_src2_v = p_src->p[V_PLANE].p_pixels +
397 p_filter->fmt_in.video.i_x_offset/2 +
398 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
400 p_trans = p_src->p[A_PLANE].p_pixels +
401 p_filter->fmt_in.video.i_x_offset +
402 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
404 #define MAX_TRANS 255
407 /* Draw until we reach the bottom of the subtitle */
408 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
409 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
410 p_src2_y += i_src2_pitch,
411 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
412 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
413 p_src2_u += i_src2_pitch,
414 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
415 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
416 p_src2_v += i_src2_pitch )
418 b_even_scanline = !b_even_scanline;
420 /* Draw until we reach the end of the line */
421 for( i_x = 0; i_x < i_width; i_x++ )
424 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
427 /* Completely transparent. Don't change pixel */
430 else if( i_trans == MAX_TRANS )
432 /* Completely opaque. Completely overwrite underlying pixel */
433 p_dst_y[i_x] = p_src2_y[i_x];
435 if( b_even_scanline && i_x % 2 == 0 )
437 p_dst_u[i_x/2] = p_src2_u[i_x];
438 p_dst_v[i_x/2] = p_src2_v[i_x];
444 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
445 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
448 if( b_even_scanline && i_x % 2 == 0 )
450 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
451 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
453 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
454 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
466 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
467 picture_t *p_dst_orig, picture_t *p_src,
468 int i_x_offset, int i_y_offset,
469 int i_width, int i_height, int i_alpha )
471 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
472 uint8_t *p_dst, *p_src1, *p_src2_y;
473 uint8_t *p_src2_u, *p_src2_v;
475 int i_x, i_y, i_pix_pitch, i_trans = 0;
478 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
479 i_dst_pitch = p_dst_pic->p->i_pitch;
480 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
481 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
482 p_dst_pic->p->i_pitch *
483 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
485 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
486 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
487 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
488 p_dst_orig->p->i_pitch *
489 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
491 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
492 p_src2_y = p_src->p[Y_PLANE].p_pixels +
493 p_filter->fmt_in.video.i_x_offset +
494 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
495 p_src2_u = p_src->p[U_PLANE].p_pixels +
496 p_filter->fmt_in.video.i_x_offset/2 +
497 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
498 p_src2_v = p_src->p[V_PLANE].p_pixels +
499 p_filter->fmt_in.video.i_x_offset/2 +
500 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
502 p_trans = p_src->p[A_PLANE].p_pixels +
503 p_filter->fmt_in.video.i_x_offset +
504 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
506 #define MAX_TRANS 255
509 /* Draw until we reach the bottom of the subtitle */
510 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
511 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
512 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
513 p_src2_v += i_src2_pitch )
515 /* Draw until we reach the end of the line */
516 for( i_x = 0; i_x < i_width; i_x++ )
519 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
522 /* Completely transparent. Don't change pixel */
525 else if( i_trans == MAX_TRANS )
527 /* Completely opaque. Completely overwrite underlying pixel */
528 yuv_to_rgb( &r, &g, &b,
529 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
531 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
536 /* FIXME: do the blending */
537 yuv_to_rgb( &r, &g, &b,
538 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
540 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
550 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
551 picture_t *p_dst_orig, picture_t *p_src,
552 int i_x_offset, int i_y_offset,
553 int i_width, int i_height, int i_alpha )
555 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
556 uint8_t *p_dst, *p_src1, *p_src2_y;
557 uint8_t *p_src2_u, *p_src2_v;
559 int i_x, i_y, i_pix_pitch, i_trans = 0;
562 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
563 i_dst_pitch = p_dst_pic->p->i_pitch;
564 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
565 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
566 p_dst_pic->p->i_pitch *
567 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
569 i_src1_pitch = p_dst_orig->p->i_pitch;
570 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
571 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
572 p_dst_orig->p->i_pitch *
573 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
575 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
576 p_src2_y = p_src->p[Y_PLANE].p_pixels +
577 p_filter->fmt_in.video.i_x_offset +
578 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
579 p_src2_u = p_src->p[U_PLANE].p_pixels +
580 p_filter->fmt_in.video.i_x_offset/2 +
581 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
582 p_src2_v = p_src->p[V_PLANE].p_pixels +
583 p_filter->fmt_in.video.i_x_offset/2 +
584 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
586 p_trans = p_src->p[A_PLANE].p_pixels +
587 p_filter->fmt_in.video.i_x_offset +
588 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
590 #define MAX_TRANS 255
593 if( (i_pix_pitch == 4)
594 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
598 ** if picture pixels are 32 bits long and lines addresses are 32 bit
599 ** aligned, optimize rendering
601 uint32_t *p32_dst = (uint32_t *)p_dst;
602 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
603 uint32_t *p32_src1 = (uint32_t *)p_src1;
604 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
606 int i_rshift, i_gshift, i_bshift;
607 uint32_t i_rmask, i_gmask, i_bmask;
609 if( p_dst_pic->p_heap )
611 i_rmask = p_dst_pic->p_heap->i_rmask;
612 i_gmask = p_dst_pic->p_heap->i_gmask;
613 i_bmask = p_dst_pic->p_heap->i_bmask;
614 i_rshift = p_dst_pic->p_heap->i_lrshift;
615 i_gshift = p_dst_pic->p_heap->i_lgshift;
616 i_bshift = p_dst_pic->p_heap->i_lbshift;
620 i_rmask = p_dst_pic->format.i_rmask;
621 i_gmask = p_dst_pic->format.i_gmask;
622 i_bmask = p_dst_pic->format.i_bmask;
624 if( (i_rmask == 0x00FF0000)
625 && (i_gmask == 0x0000FF00)
626 && (i_bmask == 0x000000FF) )
628 /* X8R8G8B8 pixel layout */
633 else if( (i_rmask == 0xFF000000)
634 && (i_gmask == 0x00FF0000)
635 && (i_bmask == 0x0000FF00) )
637 /* R8G8B8X8 pixel layout */
647 /* Draw until we reach the bottom of the subtitle */
648 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
649 p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
650 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
651 p_src2_v += i_src2_pitch )
653 /* Draw until we reach the end of the line */
654 for( i_x = 0; i_x < i_width; i_x++ )
657 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
660 /* Completely transparent. Don't change pixel */
663 else if( i_trans == MAX_TRANS )
665 /* Completely opaque. Completely overwrite underlying pixel */
666 yuv_to_rgb( &r, &g, &b,
667 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
669 p32_dst[i_x] = (r<<i_rshift)
676 uint32_t i_pix_src1 = p32_src1[i_x];
677 yuv_to_rgb( &r, &g, &b,
678 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
680 p32_dst[i_x] = ( ( r * i_trans +
681 (uint16_t)((i_pix_src1 & i_rmask)>>i_rshift) *
682 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_rshift
684 (uint16_t)((i_pix_src1 & i_gmask)>>i_gshift) *
685 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_gshift
687 (uint16_t)((i_pix_src1 & i_bmask)>>i_bshift) *
688 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_bshift;
695 int i_rindex, i_bindex, i_gindex;
696 uint32_t i_rmask, i_gmask, i_bmask;
700 i_rmask = p_dst_pic->format.i_rmask;
701 i_gmask = p_dst_pic->format.i_gmask;
702 i_bmask = p_dst_pic->format.i_bmask;
705 ** quick and dirty way to get byte index from mask
706 ** will only work correctly if mask are 8 bit aligned
707 ** and are 8 bit long
709 #ifdef WORDS_BIGENDIAN
710 i_rindex = ((i_rmask>>16) & 1)
713 i_gindex = ((i_gmask>>16) & 1)
716 i_bindex = ((i_bmask>>16) & 1)
720 i_rindex = ((i_rmask>>24) & 3)
721 | ((i_rmask>>16) & 2)
722 | ((i_rmask>>8) & 1);
723 i_gindex = ((i_gmask>>24) & 3)
724 | ((i_gmask>>16) & 2)
725 | ((i_gmask>>8) & 1);
726 i_bindex = ((i_bmask>>24) & 3)
727 | ((i_bmask>>16) & 2)
728 | ((i_bmask>>8) & 1);
731 /* Draw until we reach the bottom of the subtitle */
732 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
733 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
734 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
735 p_src2_v += i_src2_pitch )
737 /* Draw until we reach the end of the line */
738 for( i_x = 0; i_x < i_width; i_x++ )
741 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
744 /* Completely transparent. Don't change pixel */
749 int i_pos = i_x * i_pix_pitch;
750 if( i_trans == MAX_TRANS )
753 /* Completely opaque. Completely overwrite underlying pixel */
754 yuv_to_rgb( &r, &g, &b,
755 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
757 p_dst[i_pos + i_rindex ] = r;
758 p_dst[i_pos + i_gindex ] = g;
759 p_dst[i_pos + i_bindex ] = b;
763 int i_rpos = i_pos + i_rindex;
764 int i_gpos = i_pos + i_gindex;
765 int i_bpos = i_pos + i_bindex;
768 yuv_to_rgb( &r, &g, &b,
769 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
771 p_dst[i_rpos] = ( r * i_trans +
772 (uint16_t)p_src1[i_rpos] *
773 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
774 p_dst[i_gpos] = ( r * i_trans +
775 (uint16_t)p_src1[i_gpos] *
776 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
777 p_dst[i_bpos] = ( r * i_trans +
778 (uint16_t)p_src1[i_gpos] *
779 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
792 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
793 picture_t *p_dst_orig, picture_t *p_src,
794 int i_x_offset, int i_y_offset,
795 int i_width, int i_height, int i_alpha )
797 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
798 uint8_t *p_dst, *p_src1, *p_src2_y;
799 uint8_t *p_src2_u, *p_src2_v;
801 int i_x, i_y, i_pix_pitch, i_trans = 0;
802 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
803 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
805 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
811 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
817 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
825 i_dst_pitch = p_dst_pic->p->i_pitch;
826 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
827 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
828 p_dst_pic->p->i_pitch *
829 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
831 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
832 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
833 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
834 p_dst_orig->p->i_pitch *
835 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
837 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
838 p_src2_y = p_src->p[Y_PLANE].p_pixels +
839 p_filter->fmt_in.video.i_x_offset +
840 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
841 p_src2_u = p_src->p[U_PLANE].p_pixels +
842 p_filter->fmt_in.video.i_x_offset/2 +
843 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
844 p_src2_v = p_src->p[V_PLANE].p_pixels +
845 p_filter->fmt_in.video.i_x_offset/2 +
846 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
848 p_trans = p_src->p[A_PLANE].p_pixels +
849 p_filter->fmt_in.video.i_x_offset +
850 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
852 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
854 #define MAX_TRANS 255
857 /* Draw until we reach the bottom of the subtitle */
858 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
859 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
860 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
861 p_src2_v += i_src2_pitch )
863 /* Draw until we reach the end of the line */
864 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
866 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
869 /* Completely transparent. Don't change pixel */
871 else if( i_trans == MAX_TRANS )
873 /* Completely opaque. Completely overwrite underlying pixel */
874 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
878 if( p_trans[i_x+1] > 0xaa )
880 p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
881 p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
885 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
886 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
893 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_trans +
894 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
901 if( p_trans[i_x+1] > 0xaa )
903 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
904 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
911 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
912 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
914 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
915 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
927 /***********************************************************************
929 ***********************************************************************/
930 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
931 picture_t *p_dst_orig, picture_t *p_src,
932 int i_x_offset, int i_y_offset,
933 int i_width, int i_height, int i_alpha )
935 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
936 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
937 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
938 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
940 vlc_bool_t b_even_scanline = i_y_offset % 2;
942 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
943 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
944 p_filter->fmt_out.video.i_x_offset +
945 p_dst->p[Y_PLANE].i_pitch *
946 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
947 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
948 p_filter->fmt_out.video.i_x_offset/2 +
949 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
950 p_dst->p[U_PLANE].i_pitch;
951 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
952 p_filter->fmt_out.video.i_x_offset/2 +
953 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
954 p_dst->p[V_PLANE].i_pitch;
956 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
957 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
958 p_filter->fmt_out.video.i_x_offset +
959 p_dst_orig->p[Y_PLANE].i_pitch *
960 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
961 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
962 p_filter->fmt_out.video.i_x_offset/2 +
963 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
964 p_dst_orig->p[U_PLANE].i_pitch;
965 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
966 p_filter->fmt_out.video.i_x_offset/2 +
967 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
968 p_dst_orig->p[V_PLANE].i_pitch;
970 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
971 p_src2_y = p_src->p[Y_PLANE].p_pixels +
972 p_filter->fmt_in.video.i_x_offset +
973 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
974 p_src2_u = p_src->p[U_PLANE].p_pixels +
975 p_filter->fmt_in.video.i_x_offset/2 +
976 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
977 p_src2_v = p_src->p[V_PLANE].p_pixels +
978 p_filter->fmt_in.video.i_x_offset/2 +
979 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
981 #define MAX_TRANS 255
984 /* Draw until we reach the bottom of the subtitle */
985 for( i_y = 0; i_y < i_height; i_y++,
986 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
987 p_src2_y += i_src2_pitch )
989 if( b_even_scanline )
991 p_dst_u += i_dst_pitch/2;
992 p_dst_v += i_dst_pitch/2;
993 p_src1_u += i_src1_pitch/2;
994 p_src1_v += i_src1_pitch/2;
996 b_even_scanline = !b_even_scanline;
998 /* Draw until we reach the end of the line */
999 for( i_x = 0; i_x < i_width; i_x++ )
1001 if( i_alpha == MAX_TRANS )
1003 /* Completely opaque. Completely overwrite underlying pixel */
1004 p_dst_y[i_x] = p_src2_y[i_x];
1006 if( b_even_scanline && i_x % 2 == 0 )
1008 p_dst_u[i_x/2] = p_src2_u[i_x/2];
1009 p_dst_v[i_x/2] = p_src2_v[i_x/2];
1015 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1016 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_alpha) )
1019 if( b_even_scanline && i_x % 2 == 0 )
1021 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x/2] * i_alpha +
1022 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_alpha) )
1024 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x/2] * i_alpha +
1025 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_alpha) )
1031 p_src2_u += i_src2_pitch/2;
1032 p_src2_v += i_src2_pitch/2;
1041 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
1042 picture_t *p_dst_orig, picture_t *p_src,
1043 int i_x_offset, int i_y_offset,
1044 int i_width, int i_height )
1046 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1047 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
1048 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
1049 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
1051 vlc_bool_t b_even_scanline = i_y_offset % 2;
1053 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1054 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1055 p_filter->fmt_out.video.i_x_offset +
1056 p_dst->p[Y_PLANE].i_pitch *
1057 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1058 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1059 p_filter->fmt_out.video.i_x_offset/2 +
1060 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1061 p_dst->p[U_PLANE].i_pitch;
1062 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1063 p_filter->fmt_out.video.i_x_offset/2 +
1064 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1065 p_dst->p[V_PLANE].i_pitch;
1067 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1068 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1069 p_filter->fmt_out.video.i_x_offset +
1070 p_dst_orig->p[Y_PLANE].i_pitch *
1071 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1072 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1073 p_filter->fmt_out.video.i_x_offset/2 +
1074 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1075 p_dst_orig->p[U_PLANE].i_pitch;
1076 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1077 p_filter->fmt_out.video.i_x_offset/2 +
1078 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1079 p_dst_orig->p[V_PLANE].i_pitch;
1081 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1082 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1083 p_filter->fmt_in.video.i_x_offset +
1084 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1085 p_src2_u = p_src->p[U_PLANE].p_pixels +
1086 p_filter->fmt_in.video.i_x_offset/2 +
1087 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1088 p_src2_v = p_src->p[V_PLANE].p_pixels +
1089 p_filter->fmt_in.video.i_x_offset/2 +
1090 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1094 /* Draw until we reach the bottom of the subtitle */
1095 for( i_y = 0; i_y < i_height; i_y++,
1096 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1097 p_src2_y += i_src2_pitch )
1099 /* Completely opaque. Completely overwrite underlying pixel */
1100 p_filter->p_libvlc->pf_memcpy( p_dst_y, p_src2_y, i_width );
1101 if( b_even_scanline )
1103 p_dst_u += i_dst_pitch/2;
1104 p_dst_v += i_dst_pitch/2;
1105 p_src1_u += i_src1_pitch/2;
1106 p_src1_v += i_src1_pitch/2;
1110 p_filter->p_libvlc->pf_memcpy( p_dst_u, p_src2_u, i_width/2 );
1111 p_filter->p_libvlc->pf_memcpy( p_dst_v, p_src2_v, i_width/2 );
1113 b_even_scanline = !b_even_scanline;
1116 p_src2_u += i_src2_pitch/2;
1117 p_src2_v += i_src2_pitch/2;
1124 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1125 picture_t *p_dst_orig, picture_t *p_src,
1126 int i_x_offset, int i_y_offset,
1127 int i_width, int i_height, int i_alpha )
1129 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1130 uint8_t *p_dst, *p_src1, *p_src2_y;
1131 uint8_t *p_src2_u, *p_src2_v;
1132 int i_x, i_y, i_pix_pitch;
1135 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1136 i_dst_pitch = p_dst_pic->p->i_pitch;
1137 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1138 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1139 p_dst_pic->p->i_pitch *
1140 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1142 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1143 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1144 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1145 p_dst_orig->p->i_pitch *
1146 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1148 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1149 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1150 p_filter->fmt_in.video.i_x_offset +
1151 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1152 p_src2_u = p_src->p[U_PLANE].p_pixels +
1153 p_filter->fmt_in.video.i_x_offset/2 +
1154 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1155 p_src2_v = p_src->p[V_PLANE].p_pixels +
1156 p_filter->fmt_in.video.i_x_offset/2 +
1157 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1159 #define MAX_TRANS 255
1160 #define TRANS_BITS 8
1162 /* Draw until we reach the bottom of the subtitle */
1163 for( i_y = 0; i_y < i_height; i_y++,
1164 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1165 p_src2_y += i_src2_pitch )
1167 /* Draw until we reach the end of the line */
1168 for( i_x = 0; i_x < i_width; i_x++ )
1170 if( i_alpha == MAX_TRANS )
1172 /* Completely opaque. Completely overwrite underlying pixel */
1173 yuv_to_rgb( &r, &g, &b,
1174 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1176 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1181 /* FIXME: do the blending */
1182 yuv_to_rgb( &r, &g, &b,
1183 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1185 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1189 p_src2_u += i_src2_pitch/2;
1190 p_src2_v += i_src2_pitch/2;
1200 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1201 picture_t *p_dst_orig, picture_t *p_src,
1202 int i_x_offset, int i_y_offset,
1203 int i_width, int i_height, int i_alpha )
1205 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1206 uint8_t *p_dst, *p_src1, *p_src2_y;
1207 uint8_t *p_src2_u, *p_src2_v;
1208 int i_x, i_y, i_pix_pitch;
1211 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1212 i_dst_pitch = p_dst_pic->p->i_pitch;
1213 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1214 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1215 p_dst_pic->p->i_pitch *
1216 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1218 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1219 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1220 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1221 p_dst_orig->p->i_pitch *
1222 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1224 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1225 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1226 p_filter->fmt_in.video.i_x_offset +
1227 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1228 p_src2_u = p_src->p[U_PLANE].p_pixels +
1229 p_filter->fmt_in.video.i_x_offset/2 +
1230 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1231 p_src2_v = p_src->p[V_PLANE].p_pixels +
1232 p_filter->fmt_in.video.i_x_offset/2 +
1233 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1235 #define MAX_TRANS 255
1236 #define TRANS_BITS 8
1238 /* Draw until we reach the bottom of the subtitle */
1239 for( i_y = 0; i_y < i_height; i_y++,
1240 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1241 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1242 p_src2_v += i_src2_pitch )
1244 /* Draw until we reach the end of the line */
1245 for( i_x = 0; i_x < i_width; i_x++ )
1247 if( i_alpha == MAX_TRANS )
1249 /* Completely opaque. Completely overwrite underlying pixel */
1250 yuv_to_rgb( &r, &g, &b,
1251 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1253 p_dst[i_x * i_pix_pitch] = r;
1254 p_dst[i_x * i_pix_pitch + 1] = g;
1255 p_dst[i_x * i_pix_pitch + 2] = b;
1260 yuv_to_rgb( &r, &g, &b,
1261 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1263 p_dst[i_x * i_pix_pitch] = ( r * i_alpha +
1264 (uint16_t)p_src1[i_x * i_pix_pitch] *
1265 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1266 p_dst[i_x * i_pix_pitch + 1] = ( g * i_alpha +
1267 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1268 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1269 p_dst[i_x * i_pix_pitch + 2] = ( b * i_alpha +
1270 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1271 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1275 p_src2_u += i_src2_pitch/2;
1276 p_src2_v += i_src2_pitch/2;
1286 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1287 picture_t *p_dst_orig, picture_t *p_src,
1288 int i_x_offset, int i_y_offset,
1289 int i_width, int i_height, int i_alpha )
1291 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1292 uint8_t *p_dst, *p_src1, *p_src2_y;
1293 uint8_t *p_src2_u, *p_src2_v;
1294 int i_x, i_y, i_pix_pitch;
1295 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1296 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1298 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1304 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1310 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1318 i_dst_pitch = p_dst_pic->p->i_pitch;
1319 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1320 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1321 p_dst_pic->p->i_pitch *
1322 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1324 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1325 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1326 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1327 p_dst_orig->p->i_pitch *
1328 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1330 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1331 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1332 p_filter->fmt_in.video.i_x_offset +
1333 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1334 p_src2_u = p_src->p[U_PLANE].p_pixels +
1335 p_filter->fmt_in.video.i_x_offset/2 +
1336 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1337 p_src2_v = p_src->p[V_PLANE].p_pixels +
1338 p_filter->fmt_in.video.i_x_offset/2 +
1339 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1341 i_width &= ~1; /* Needs to be a multiple of 2 */
1343 #define MAX_TRANS 255
1344 #define TRANS_BITS 8
1346 /* Draw until we reach the bottom of the subtitle */
1347 for( i_y = 0; i_y < i_height; i_y++,
1348 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1349 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1350 p_src2_v += i_src2_pitch )
1352 /* Draw until we reach the end of the line */
1353 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1355 if( i_alpha == MAX_TRANS )
1357 /* Completely opaque. Completely overwrite underlying pixel */
1358 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
1362 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x/2];
1363 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x/2];
1369 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1370 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_alpha) )
1375 uint16_t i_u = p_src2_u[i_x/2];
1376 uint16_t i_v = p_src2_v[i_x/2];
1377 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_alpha +
1378 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_alpha) )
1380 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_alpha +
1381 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_alpha) )
1388 p_src2_u += i_src2_pitch/2;
1389 p_src2_v += i_src2_pitch/2;
1399 /***********************************************************************
1401 ***********************************************************************/
1402 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1403 picture_t *p_dst_orig, picture_t *p_src,
1404 int i_x_offset, int i_y_offset,
1405 int i_width, int i_height, int i_alpha )
1407 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1408 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1409 uint8_t *p_src1_u, *p_dst_u;
1410 uint8_t *p_src1_v, *p_dst_v;
1411 int i_x, i_y, i_trans;
1412 vlc_bool_t b_even_scanline = i_y_offset % 2;
1414 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1415 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1416 p_filter->fmt_out.video.i_x_offset +
1417 p_dst->p[Y_PLANE].i_pitch *
1418 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1419 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1420 p_filter->fmt_out.video.i_x_offset/2 +
1421 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1422 p_dst->p[U_PLANE].i_pitch;
1423 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1424 p_filter->fmt_out.video.i_x_offset/2 +
1425 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1426 p_dst->p[V_PLANE].i_pitch;
1428 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1429 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1430 p_filter->fmt_out.video.i_x_offset +
1431 p_dst_orig->p[Y_PLANE].i_pitch *
1432 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1433 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1434 p_filter->fmt_out.video.i_x_offset/2 +
1435 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1436 p_dst_orig->p[U_PLANE].i_pitch;
1437 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1438 p_filter->fmt_out.video.i_x_offset/2 +
1439 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1440 p_dst_orig->p[V_PLANE].i_pitch;
1442 i_src2_pitch = p_src->p->i_pitch;
1443 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1444 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1446 #define MAX_TRANS 255
1447 #define TRANS_BITS 8
1448 #define p_trans p_src2
1449 #define p_pal p_filter->fmt_in.video.p_palette->palette
1451 /* Draw until we reach the bottom of the subtitle */
1452 for( i_y = 0; i_y < i_height; i_y++,
1453 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1454 p_src2 += i_src2_pitch,
1455 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1456 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1457 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1458 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1460 b_even_scanline = !b_even_scanline;
1462 /* Draw until we reach the end of the line */
1463 for( i_x = 0; i_x < i_width; i_x++ )
1465 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1468 /* Completely transparent. Don't change pixel */
1471 else if( i_trans == MAX_TRANS )
1473 /* Completely opaque. Completely overwrite underlying pixel */
1474 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
1476 if( b_even_scanline && ((i_x % 2) == 0) )
1478 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
1479 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
1485 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
1486 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1489 if( b_even_scanline && ((i_x % 2) == 0) )
1491 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
1492 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1494 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
1495 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1509 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1510 picture_t *p_dst_orig, picture_t *p_src,
1511 int i_x_offset, int i_y_offset,
1512 int i_width, int i_height, int i_alpha )
1514 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1515 uint8_t *p_src1, *p_src2, *p_dst;
1516 int i_x, i_y, i_pix_pitch, i_trans;
1517 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1518 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1520 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1526 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1532 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1540 i_dst_pitch = p_dst_pic->p->i_pitch;
1541 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1542 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1543 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1545 i_src1_pitch = p_dst_orig->p->i_pitch;
1546 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1547 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1548 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1550 i_src2_pitch = p_src->p->i_pitch;
1551 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1552 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1554 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1556 #define MAX_TRANS 255
1557 #define TRANS_BITS 8
1558 #define p_trans p_src2
1559 #define p_pal p_filter->fmt_in.video.p_palette->palette
1561 /* Draw until we reach the bottom of the subtitle */
1562 for( i_y = 0; i_y < i_height; i_y++,
1563 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1565 /* Draw until we reach the end of the line */
1566 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1568 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1571 /* Completely transparent. Don't change pixel */
1573 else if( i_trans == MAX_TRANS )
1575 /* Completely opaque. Completely overwrite underlying pixel */
1576 p_dst[i_x * 2 + i_l_offset] = p_pal[p_src2[i_x]][0];
1580 if( p_trans[i_x+1] > 0xaa )
1582 p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1583 p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1587 p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1588 p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1595 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1596 i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1597 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1603 if( p_trans[i_x+1] > 0xaa )
1605 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1606 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1610 i_u = p_pal[p_src2[i_x]][1];
1611 i_v = p_pal[p_src2[i_x]][2];
1614 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1615 i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1616 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1617 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1618 i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1619 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1633 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1634 picture_t *p_dst_orig, picture_t *p_src,
1635 int i_x_offset, int i_y_offset,
1636 int i_width, int i_height, int i_alpha )
1638 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1639 uint8_t *p_src1, *p_src2, *p_dst;
1640 int i_x, i_y, i_pix_pitch, i_trans;
1642 video_palette_t rgbpalette;
1644 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1645 i_dst_pitch = p_dst_pic->p->i_pitch;
1646 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1647 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1648 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1650 i_src1_pitch = p_dst_orig->p->i_pitch;
1651 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1652 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1653 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1655 i_src2_pitch = p_src->p->i_pitch;
1656 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1657 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1659 #define MAX_TRANS 255
1660 #define TRANS_BITS 8
1661 #define p_trans p_src2
1662 #define p_pal p_filter->fmt_in.video.p_palette->palette
1663 #define rgbpal rgbpalette.palette
1665 /* Convert palette first */
1666 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1669 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1671 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1673 *(uint16_t *)rgbpal[i_y] =
1674 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1678 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1682 /* Draw until we reach the bottom of the subtitle */
1683 for( i_y = 0; i_y < i_height; i_y++,
1684 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1686 /* Draw until we reach the end of the line */
1687 for( i_x = 0; i_x < i_width; i_x++ )
1689 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1692 /* Completely transparent. Don't change pixel */
1695 else if( i_trans == MAX_TRANS ||
1696 p_filter->fmt_out.video.i_chroma ==
1697 VLC_FOURCC('R','V','1','6') )
1699 /* Completely opaque. Completely overwrite underlying pixel */
1700 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1701 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1702 if( p_filter->fmt_out.video.i_chroma !=
1703 VLC_FOURCC('R','V','1','6') )
1704 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1709 p_dst[i_x * i_pix_pitch] = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1710 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1711 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1712 p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1713 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1714 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1715 p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1716 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1717 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1730 /***********************************************************************
1732 ***********************************************************************/
1733 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1734 picture_t *p_dst_orig, picture_t *p_src,
1735 int i_x_offset, int i_y_offset,
1736 int i_width, int i_height, int i_alpha )
1738 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1739 uint8_t *p_src1_y, *p_dst_y;
1740 uint8_t *p_src1_u, *p_dst_u;
1741 uint8_t *p_src1_v, *p_dst_v;
1743 int i_x, i_y, i_trans;
1746 vlc_bool_t b_even_scanline = i_y_offset % 2;
1748 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1749 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1750 p_filter->fmt_out.video.i_x_offset +
1751 p_dst->p[Y_PLANE].i_pitch *
1752 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1753 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1754 p_filter->fmt_out.video.i_x_offset/2 +
1755 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1756 p_dst->p[U_PLANE].i_pitch;
1757 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1758 p_filter->fmt_out.video.i_x_offset/2 +
1759 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1760 p_dst->p[V_PLANE].i_pitch;
1762 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1763 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1764 p_filter->fmt_out.video.i_x_offset +
1765 p_dst_orig->p[Y_PLANE].i_pitch *
1766 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1767 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1768 p_filter->fmt_out.video.i_x_offset/2 +
1769 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1770 p_dst_orig->p[U_PLANE].i_pitch;
1771 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1772 p_filter->fmt_out.video.i_x_offset/2 +
1773 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1774 p_dst_orig->p[V_PLANE].i_pitch;
1776 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1777 i_src2_pitch = p_src->p->i_pitch;
1778 p_src2 = p_src->p->p_pixels +
1779 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1780 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1783 #define MAX_TRANS 255
1784 #define TRANS_BITS 8
1786 /* Draw until we reach the bottom of the subtitle */
1787 for( i_y = 0; i_y < i_height; i_y++,
1788 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1789 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1790 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1791 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1792 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1793 p_src2 += i_src2_pitch )
1795 b_even_scanline = !b_even_scanline;
1797 /* Draw until we reach the end of the line */
1798 for( i_x = 0; i_x < i_width; i_x++ )
1800 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1801 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1802 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1803 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1806 /* Completely transparent. Don't change pixel */
1809 else if( i_trans == MAX_TRANS )
1811 /* Completely opaque. Completely overwrite underlying pixel */
1812 rgb_to_yuv( &y, &u, &v, R, G, B );
1815 if( b_even_scanline && i_x % 2 == 0 )
1824 rgb_to_yuv( &y, &u, &v, R, G, B );
1825 p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1826 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1829 if( b_even_scanline && i_x % 2 == 0 )
1831 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1832 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1834 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1835 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1850 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1851 picture_t *p_dst_orig, picture_t *p_src,
1852 int i_x_offset, int i_y_offset,
1853 int i_width, int i_height, int i_alpha )
1855 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1856 uint8_t *p_dst, *p_src1, *p_src2;
1857 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1859 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1860 i_dst_pitch = p_dst_pic->p->i_pitch;
1861 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1862 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1863 p_dst_pic->p->i_pitch *
1864 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1866 i_src1_pitch = p_dst_orig->p->i_pitch;
1867 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1868 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1869 p_dst_orig->p->i_pitch *
1870 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1872 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1873 i_src2_pitch = p_src->p->i_pitch;
1874 p_src2 = p_src->p->p_pixels +
1875 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1876 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1878 #define MAX_TRANS 255
1879 #define TRANS_BITS 8
1881 /* Draw until we reach the bottom of the subtitle */
1882 for( i_y = 0; i_y < i_height; i_y++,
1883 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1885 /* Draw until we reach the end of the line */
1886 for( i_x = 0; i_x < i_width; i_x++ )
1888 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1889 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1890 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1891 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1894 /* Completely transparent. Don't change pixel */
1897 else if( i_trans == MAX_TRANS )
1899 /* Completely opaque. Completely overwrite underlying pixel */
1900 p_dst[i_x * i_pix_pitch + 0] = R;
1901 p_dst[i_x * i_pix_pitch + 1] = G;
1902 p_dst[i_x * i_pix_pitch + 2] = B;
1907 p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1908 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1909 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1910 p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1911 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1912 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1913 p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1914 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1915 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1928 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1929 picture_t *p_dst_orig, picture_t *p_src,
1930 int i_x_offset, int i_y_offset,
1931 int i_width, int i_height, int i_alpha )
1933 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1934 uint8_t *p_dst, *p_src1, *p_src2;
1935 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1938 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1939 i_dst_pitch = p_dst_pic->p->i_pitch;
1940 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1941 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1942 p_dst_pic->p->i_pitch *
1943 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1945 i_src1_pitch = p_dst_orig->p->i_pitch;
1946 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1947 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1948 p_dst_orig->p->i_pitch *
1949 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1951 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1952 i_src2_pitch = p_src->p->i_pitch;
1953 p_src2 = p_src->p->p_pixels +
1954 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1955 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1957 #define MAX_TRANS 255
1958 #define TRANS_BITS 8
1960 /* Draw until we reach the bottom of the subtitle */
1961 for( i_y = 0; i_y < i_height; i_y++,
1962 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1964 /* Draw until we reach the end of the line */
1965 for( i_x = 0; i_x < i_width; i_x++ )
1967 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1968 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1969 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1970 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1973 /* Completely transparent. Don't change pixel */
1976 else if( i_trans == MAX_TRANS )
1978 /* Completely opaque. Completely overwrite underlying pixel */
1979 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1984 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1985 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1986 ( ( ( (R >> 3)*i_trans
1987 + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1988 >> TRANS_BITS ) << 11 )
1989 | ( ( ( (G >> 2)*i_trans
1990 + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1991 >> TRANS_BITS ) << 5 )
1992 | ( ( ( (B >> 3)*i_trans
1993 + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
2007 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
2008 picture_t *p_dst_orig, picture_t *p_src,
2009 int i_x_offset, int i_y_offset,
2010 int i_width, int i_height, int i_alpha )
2012 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
2013 uint8_t *p_dst, *p_src1, *p_src2;
2015 int i_x, i_y, i_pix_pitch, i_trans;
2016 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
2017 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
2020 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
2026 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
2032 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
2040 i_dst_pitch = p_dst_pic->p->i_pitch;
2041 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
2042 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2043 p_dst_pic->p->i_pitch *
2044 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2046 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
2047 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
2048 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2049 p_dst_orig->p->i_pitch *
2050 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2052 i_src_pix_pitch = p_src->p->i_pixel_pitch;
2053 i_src2_pitch = p_src->p->i_pitch;
2054 p_src2 = p_src->p->p_pixels +
2055 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
2056 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
2058 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
2060 #define MAX_TRANS 255
2061 #define TRANS_BITS 8
2063 /* Draw until we reach the bottom of the subtitle */
2064 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
2065 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
2066 p_src2 += i_src2_pitch )
2068 /* Draw until we reach the end of the line */
2069 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
2071 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
2072 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
2073 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
2074 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
2077 /* Completely transparent. Don't change pixel */
2079 else if( i_trans == MAX_TRANS )
2081 /* Completely opaque. Completely overwrite underlying pixel */
2082 rgb_to_yuv( &y, &u, &v, R, G, B );
2083 p_dst[i_x * 2 + i_l_offset] = y;
2087 p_dst[i_x * 2 + i_u_offset] = u;
2088 p_dst[i_x * 2 + i_v_offset] = v;
2094 rgb_to_yuv( &y, &u, &v, R, G, B );
2095 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)y * i_trans +
2096 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
2101 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
2102 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
2104 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
2105 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )