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 BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
62 int, int, int, int, int );
63 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
64 int, int, int, int, int );
65 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
66 int, int, int, int, int );
69 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
70 int, int, int, int, int );
71 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
72 picture_t *, int, int, int, int, int );
73 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
74 int, int, int, int, int );
75 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
76 int, int, int, int, int );
78 /*****************************************************************************
80 *****************************************************************************/
82 set_description( _("Video pictures blending") );
83 set_capability( "video blending", 100 );
84 set_callbacks( OpenFilter, CloseFilter );
87 /*****************************************************************************
88 * OpenFilter: probe the filter and return score
89 *****************************************************************************/
90 static int OpenFilter( vlc_object_t *p_this )
92 filter_t *p_filter = (filter_t*)p_this;
95 /* Check if we can handle that format.
96 * We could try to use a chroma filter if we can't. */
97 int in_chroma = p_filter->fmt_in.video.i_chroma;
98 int out_chroma = p_filter->fmt_out.video.i_chroma;
99 if( ( in_chroma != VLC_FOURCC('Y','U','V','A') &&
100 in_chroma != VLC_FOURCC('Y','U','V','P') &&
101 in_chroma != VLC_FOURCC('R','G','B','A') ) ||
102 ( out_chroma != VLC_FOURCC('I','4','2','0') &&
103 out_chroma != VLC_FOURCC('Y','U','Y','2') &&
104 out_chroma != VLC_FOURCC('Y','V','1','2') &&
105 out_chroma != VLC_FOURCC('U','Y','V','Y') &&
106 out_chroma != VLC_FOURCC('Y','V','Y','U') &&
107 out_chroma != VLC_FOURCC('R','V','1','6') &&
108 out_chroma != VLC_FOURCC('R','V','2','4') &&
109 out_chroma != VLC_FOURCC('R','V','3','2') ) )
114 /* Allocate the memory needed to store the decoder's structure */
115 if( ( p_filter->p_sys = p_sys =
116 (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
118 msg_Err( p_filter, "out of memory" );
123 p_filter->pf_video_blend = Blend;
125 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
126 (char *)&p_filter->fmt_in.video.i_chroma,
127 (char *)&p_filter->fmt_out.video.i_chroma );
133 /*****************************************************************************
134 * CloseFilter: clean up the filter
135 *****************************************************************************/
136 static void CloseFilter( vlc_object_t *p_this )
138 filter_t *p_filter = (filter_t*)p_this;
139 filter_sys_t *p_sys = p_filter->p_sys;
144 /****************************************************************************
145 * Blend: the whole thing
146 ****************************************************************************
147 * This function is called just after the thread is launched.
148 ****************************************************************************/
149 static void Blend( filter_t *p_filter, picture_t *p_dst,
150 picture_t *p_dst_orig, picture_t *p_src,
151 int i_x_offset, int i_y_offset, int i_alpha )
153 int i_width, i_height;
155 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
156 (int)p_filter->fmt_in.video.i_visible_width);
158 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
159 (int)p_filter->fmt_in.video.i_visible_height);
161 if( i_width <= 0 || i_height <= 0 ) return;
164 printf( "chroma: %4.4s -> %4.4s\n",
165 (char *)&p_filter->fmt_in.video.i_chroma,
166 (char *)&p_filter->fmt_out.video.i_chroma );
169 switch( p_filter->fmt_in.video.i_chroma )
171 case VLC_FOURCC('Y','U','V','A'):
172 switch( p_filter->fmt_out.video.i_chroma )
174 case VLC_FOURCC('I','4','2','0'):
175 case VLC_FOURCC('Y','V','1','2'):
176 BlendI420( p_filter, p_dst, p_dst_orig, p_src,
177 i_x_offset, i_y_offset,
178 i_width, i_height, i_alpha );
180 case VLC_FOURCC('Y','U','Y','2'):
181 case VLC_FOURCC('U','Y','V','Y'):
182 case VLC_FOURCC('Y','V','Y','U'):
183 BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
184 i_x_offset, i_y_offset,
185 i_width, i_height, i_alpha );
187 case VLC_FOURCC('R','V','1','6'):
188 BlendR16( p_filter, p_dst, p_dst_orig, p_src,
189 i_x_offset, i_y_offset,
190 i_width, i_height, i_alpha );
192 case VLC_FOURCC('R','V','2','4'):
193 case VLC_FOURCC('R','V','3','2'):
194 BlendR24( p_filter, p_dst, p_dst_orig, p_src,
195 i_x_offset, i_y_offset,
196 i_width, i_height, i_alpha );
199 case VLC_FOURCC('Y','U','V','P'):
200 switch( p_filter->fmt_out.video.i_chroma )
202 case VLC_FOURCC('I','4','2','0'):
203 case VLC_FOURCC('Y','V','1','2'):
204 BlendPalI420( 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('Y','U','Y','2'):
209 case VLC_FOURCC('U','Y','V','Y'):
210 case VLC_FOURCC('Y','V','Y','U'):
211 BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
212 i_x_offset, i_y_offset,
213 i_width, i_height, i_alpha );
215 case VLC_FOURCC('R','V','1','6'):
216 case VLC_FOURCC('R','V','2','4'):
217 case VLC_FOURCC('R','V','3','2'):
218 BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
219 i_x_offset, i_y_offset,
220 i_width, i_height, i_alpha );
223 case VLC_FOURCC('R','G','B','A'):
224 switch( p_filter->fmt_out.video.i_chroma )
226 case VLC_FOURCC('I','4','2','0'):
227 case VLC_FOURCC('Y','V','1','2'):
228 BlendRGBAI420( 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('Y','U','Y','2'):
233 case VLC_FOURCC('U','Y','V','Y'):
234 case VLC_FOURCC('Y','V','Y','U'):
235 BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
236 i_x_offset, i_y_offset,
237 i_width, i_height, i_alpha );
239 case VLC_FOURCC('R','V','2','4'):
240 case VLC_FOURCC('R','V','3','2'):
241 BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
242 i_x_offset, i_y_offset,
243 i_width, i_height, i_alpha );
245 case VLC_FOURCC('R','V','1','6'):
246 BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
247 i_x_offset, i_y_offset,
248 i_width, i_height, i_alpha );
253 msg_Dbg( p_filter, "no matching alpha blending routine "
254 "(chroma: %4.4s -> %4.4s)",
255 (char *)&p_filter->fmt_in.video.i_chroma,
256 (char *)&p_filter->fmt_out.video.i_chroma );
259 /***********************************************************************
261 ***********************************************************************/
262 static inline void yuv_to_rgb( int *r, int *g, int *b,
263 uint8_t y1, uint8_t u1, uint8_t v1 )
265 /* macros used for YUV pixel conversions */
266 # define SCALEBITS 10
267 # define ONE_HALF (1 << (SCALEBITS - 1))
268 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
269 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
271 int y, cb, cr, r_add, g_add, b_add;
275 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
276 g_add = - FIX(0.34414*255.0/224.0) * cb
277 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
278 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
279 y = (y1 - 16) * FIX(255.0/219.0);
280 *r = CLAMP((y + r_add) >> SCALEBITS);
281 *g = CLAMP((y + g_add) >> SCALEBITS);
282 *b = CLAMP((y + b_add) >> SCALEBITS);
285 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
286 int r, int g, int b )
288 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
289 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
290 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
293 /***********************************************************************
295 ***********************************************************************/
296 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
297 picture_t *p_dst_orig, picture_t *p_src,
298 int i_x_offset, int i_y_offset,
299 int i_width, int i_height, int i_alpha )
301 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
302 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
303 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
304 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
306 int i_x, i_y, i_trans;
307 vlc_bool_t b_even_scanline = i_y_offset % 2;
309 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
310 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
311 p_filter->fmt_out.video.i_x_offset +
312 p_dst->p[Y_PLANE].i_pitch *
313 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
314 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
315 p_filter->fmt_out.video.i_x_offset/2 +
316 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
317 p_dst->p[U_PLANE].i_pitch;
318 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
319 p_filter->fmt_out.video.i_x_offset/2 +
320 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
321 p_dst->p[V_PLANE].i_pitch;
323 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
324 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
325 p_filter->fmt_out.video.i_x_offset +
326 p_dst_orig->p[Y_PLANE].i_pitch *
327 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
328 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
329 p_filter->fmt_out.video.i_x_offset/2 +
330 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
331 p_dst_orig->p[U_PLANE].i_pitch;
332 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
333 p_filter->fmt_out.video.i_x_offset/2 +
334 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
335 p_dst_orig->p[V_PLANE].i_pitch;
337 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
338 p_src2_y = p_src->p[Y_PLANE].p_pixels +
339 p_filter->fmt_in.video.i_x_offset +
340 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
341 p_src2_u = p_src->p[U_PLANE].p_pixels +
342 p_filter->fmt_in.video.i_x_offset/2 +
343 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
344 p_src2_v = p_src->p[V_PLANE].p_pixels +
345 p_filter->fmt_in.video.i_x_offset/2 +
346 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
348 p_trans = p_src->p[A_PLANE].p_pixels +
349 p_filter->fmt_in.video.i_x_offset +
350 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
352 #define MAX_TRANS 255
355 /* Draw until we reach the bottom of the subtitle */
356 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
357 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
358 p_src2_y += i_src2_pitch,
359 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
360 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
361 p_src2_u += i_src2_pitch,
362 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
363 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
364 p_src2_v += i_src2_pitch )
366 b_even_scanline = !b_even_scanline;
368 /* Draw until we reach the end of the line */
369 for( i_x = 0; i_x < i_width; i_x++ )
371 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
374 /* Completely transparent. Don't change pixel */
377 else if( i_trans == MAX_TRANS )
379 /* Completely opaque. Completely overwrite underlying pixel */
380 p_dst_y[i_x] = p_src2_y[i_x];
382 if( b_even_scanline && i_x % 2 == 0 )
384 p_dst_u[i_x/2] = p_src2_u[i_x];
385 p_dst_v[i_x/2] = p_src2_v[i_x];
391 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
392 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
395 if( b_even_scanline && i_x % 2 == 0 )
397 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
398 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
400 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
401 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
413 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
414 picture_t *p_dst_orig, picture_t *p_src,
415 int i_x_offset, int i_y_offset,
416 int i_width, int i_height, int i_alpha )
418 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
419 uint8_t *p_dst, *p_src1, *p_src2_y;
420 uint8_t *p_src2_u, *p_src2_v;
422 int i_x, i_y, i_pix_pitch;
425 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
426 i_dst_pitch = p_dst_pic->p->i_pitch;
427 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
428 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
429 p_dst_pic->p->i_pitch *
430 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
432 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
433 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
434 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
435 p_dst_orig->p->i_pitch *
436 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
438 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
439 p_src2_y = p_src->p[Y_PLANE].p_pixels +
440 p_filter->fmt_in.video.i_x_offset +
441 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
442 p_src2_u = p_src->p[U_PLANE].p_pixels +
443 p_filter->fmt_in.video.i_x_offset/2 +
444 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
445 p_src2_v = p_src->p[V_PLANE].p_pixels +
446 p_filter->fmt_in.video.i_x_offset/2 +
447 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
449 p_trans = p_src->p[A_PLANE].p_pixels +
450 p_filter->fmt_in.video.i_x_offset +
451 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
453 #define MAX_TRANS 255
456 /* Draw until we reach the bottom of the subtitle */
457 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
458 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
459 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
460 p_src2_v += i_src2_pitch )
462 /* Draw until we reach the end of the line */
463 for( i_x = 0; i_x < i_width; i_x++ )
467 /* Completely transparent. Don't change pixel */
470 else if( p_trans[i_x] == MAX_TRANS )
472 /* Completely opaque. Completely overwrite underlying pixel */
473 yuv_to_rgb( &r, &g, &b,
474 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
476 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
481 yuv_to_rgb( &r, &g, &b,
482 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
484 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
494 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
495 picture_t *p_dst_orig, picture_t *p_src,
496 int i_x_offset, int i_y_offset,
497 int i_width, int i_height, int i_alpha )
499 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
500 uint8_t *p_dst, *p_src1, *p_src2_y;
501 uint8_t *p_src2_u, *p_src2_v;
503 int i_x, i_y, i_pix_pitch, i_trans;
506 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
507 i_dst_pitch = p_dst_pic->p->i_pitch;
508 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
509 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
510 p_dst_pic->p->i_pitch *
511 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
513 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
514 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
515 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
516 p_dst_orig->p->i_pitch *
517 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
519 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
520 p_src2_y = p_src->p[Y_PLANE].p_pixels +
521 p_filter->fmt_in.video.i_x_offset +
522 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
523 p_src2_u = p_src->p[U_PLANE].p_pixels +
524 p_filter->fmt_in.video.i_x_offset/2 +
525 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
526 p_src2_v = p_src->p[V_PLANE].p_pixels +
527 p_filter->fmt_in.video.i_x_offset/2 +
528 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
530 p_trans = p_src->p[A_PLANE].p_pixels +
531 p_filter->fmt_in.video.i_x_offset +
532 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
534 #define MAX_TRANS 255
537 /* Draw until we reach the bottom of the subtitle */
538 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
539 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
540 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
541 p_src2_v += i_src2_pitch )
543 /* Draw until we reach the end of the line */
544 for( i_x = 0; i_x < i_width; i_x++ )
546 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
549 /* Completely transparent. Don't change pixel */
552 else if( i_trans == MAX_TRANS )
554 /* Completely opaque. Completely overwrite underlying pixel */
555 yuv_to_rgb( &r, &g, &b,
556 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
558 p_dst[i_x * i_pix_pitch] = r;
559 p_dst[i_x * i_pix_pitch + 1] = g;
560 p_dst[i_x * i_pix_pitch + 2] = b;
565 yuv_to_rgb( &r, &g, &b,
566 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
568 p_dst[i_x * i_pix_pitch] = ( r * i_trans +
569 (uint16_t)p_src1[i_x * i_pix_pitch] *
570 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
571 p_dst[i_x * i_pix_pitch + 1] = ( g * i_trans +
572 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
573 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
574 p_dst[i_x * i_pix_pitch + 2] = ( b * i_trans +
575 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
576 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
586 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
587 picture_t *p_dst_orig, picture_t *p_src,
588 int i_x_offset, int i_y_offset,
589 int i_width, int i_height, int i_alpha )
591 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
592 uint8_t *p_dst, *p_src1, *p_src2_y;
593 uint8_t *p_src2_u, *p_src2_v;
595 int i_x, i_y, i_pix_pitch, i_trans;
596 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
597 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
599 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
605 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
611 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
619 i_dst_pitch = p_dst_pic->p->i_pitch;
620 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
621 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
622 p_dst_pic->p->i_pitch *
623 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
625 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
626 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
627 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
628 p_dst_orig->p->i_pitch *
629 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
631 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
632 p_src2_y = p_src->p[Y_PLANE].p_pixels +
633 p_filter->fmt_in.video.i_x_offset +
634 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
635 p_src2_u = p_src->p[U_PLANE].p_pixels +
636 p_filter->fmt_in.video.i_x_offset/2 +
637 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
638 p_src2_v = p_src->p[V_PLANE].p_pixels +
639 p_filter->fmt_in.video.i_x_offset/2 +
640 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
642 p_trans = p_src->p[A_PLANE].p_pixels +
643 p_filter->fmt_in.video.i_x_offset +
644 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
646 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
648 #define MAX_TRANS 255
651 /* Draw until we reach the bottom of the subtitle */
652 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
653 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
654 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
655 p_src2_v += i_src2_pitch )
657 /* Draw until we reach the end of the line */
658 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
660 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
663 /* Completely transparent. Don't change pixel */
665 else if( i_trans == MAX_TRANS )
667 /* Completely opaque. Completely overwrite underlying pixel */
668 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
672 if( p_trans[i_x+1] > 0xaa )
674 p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
675 p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
679 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
680 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
687 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_trans +
688 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
695 if( p_trans[i_x+1] > 0xaa )
697 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
698 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
705 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
706 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
708 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
709 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
722 /***********************************************************************
724 ***********************************************************************/
725 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
726 picture_t *p_dst_orig, picture_t *p_src,
727 int i_x_offset, int i_y_offset,
728 int i_width, int i_height, int i_alpha )
730 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
731 uint8_t *p_src1_y, *p_src2, *p_dst_y;
732 uint8_t *p_src1_u, *p_dst_u;
733 uint8_t *p_src1_v, *p_dst_v;
734 int i_x, i_y, i_trans;
735 vlc_bool_t b_even_scanline = i_y_offset % 2;
737 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
738 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
739 p_filter->fmt_out.video.i_x_offset +
740 p_dst->p[Y_PLANE].i_pitch *
741 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
742 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
743 p_filter->fmt_out.video.i_x_offset/2 +
744 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
745 p_dst->p[U_PLANE].i_pitch;
746 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
747 p_filter->fmt_out.video.i_x_offset/2 +
748 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
749 p_dst->p[V_PLANE].i_pitch;
751 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
752 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
753 p_filter->fmt_out.video.i_x_offset +
754 p_dst_orig->p[Y_PLANE].i_pitch *
755 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
756 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
757 p_filter->fmt_out.video.i_x_offset/2 +
758 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
759 p_dst_orig->p[U_PLANE].i_pitch;
760 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
761 p_filter->fmt_out.video.i_x_offset/2 +
762 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
763 p_dst_orig->p[V_PLANE].i_pitch;
765 i_src2_pitch = p_src->p->i_pitch;
766 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
767 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
769 #define MAX_TRANS 255
771 #define p_trans p_src2
772 #define p_pal p_filter->fmt_in.video.p_palette->palette
774 /* Draw until we reach the bottom of the subtitle */
775 for( i_y = 0; i_y < i_height; i_y++,
776 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
777 p_src2 += i_src2_pitch,
778 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
779 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
780 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
781 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
783 b_even_scanline = !b_even_scanline;
785 /* Draw until we reach the end of the line */
786 for( i_x = 0; i_x < i_width; i_x++ )
788 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
791 /* Completely transparent. Don't change pixel */
794 else if( i_trans == MAX_TRANS )
796 /* Completely opaque. Completely overwrite underlying pixel */
797 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
799 if( b_even_scanline && i_x % 2 == 0 )
801 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
802 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
808 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
809 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
812 if( b_even_scanline && i_x % 2 == 0 )
814 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
815 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
817 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
818 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
832 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
833 picture_t *p_dst_orig, picture_t *p_src,
834 int i_x_offset, int i_y_offset,
835 int i_width, int i_height, int i_alpha )
837 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
838 uint8_t *p_src1, *p_src2, *p_dst;
839 int i_x, i_y, i_pix_pitch, i_trans;
840 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
841 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
843 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
849 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
855 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
863 i_dst_pitch = p_dst_pic->p->i_pitch;
864 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
865 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
866 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
868 i_src1_pitch = p_dst_orig->p->i_pitch;
869 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
870 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
871 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
873 i_src2_pitch = p_src->p->i_pitch;
874 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
875 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
877 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
879 #define MAX_TRANS 255
881 #define p_trans p_src2
882 #define p_pal p_filter->fmt_in.video.p_palette->palette
884 /* Draw until we reach the bottom of the subtitle */
885 for( i_y = 0; i_y < i_height; i_y++,
886 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
888 /* Draw until we reach the end of the line */
889 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
891 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
894 /* Completely transparent. Don't change pixel */
896 else if( i_trans == MAX_TRANS )
898 /* Completely opaque. Completely overwrite underlying pixel */
899 p_dst[i_x * 2 + i_l_offset] = p_pal[p_src2[i_x]][0];
903 if( p_trans[i_x+1] > 0xaa )
905 p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
906 p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
910 p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
911 p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
918 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
919 i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
920 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
926 if( p_trans[i_x+1] > 0xaa )
928 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
929 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
933 i_u = p_pal[p_src2[i_x]][1];
934 i_v = p_pal[p_src2[i_x]][2];
937 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
938 i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
939 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
940 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
941 i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
942 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
956 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
957 picture_t *p_dst_orig, picture_t *p_src,
958 int i_x_offset, int i_y_offset,
959 int i_width, int i_height, int i_alpha )
961 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
962 uint8_t *p_src1, *p_src2, *p_dst;
963 int i_x, i_y, i_pix_pitch, i_trans;
965 video_palette_t rgbpalette;
967 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
968 i_dst_pitch = p_dst_pic->p->i_pitch;
969 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
970 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
971 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
973 i_src1_pitch = p_dst_orig->p->i_pitch;
974 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
975 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
976 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
978 i_src2_pitch = p_src->p->i_pitch;
979 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
980 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
982 #define MAX_TRANS 255
984 #define p_trans p_src2
985 #define p_pal p_filter->fmt_in.video.p_palette->palette
986 #define rgbpal rgbpalette.palette
988 /* Convert palette first */
989 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
992 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
994 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
996 *(uint16_t *)rgbpal[i_y] =
997 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1001 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1005 /* Draw until we reach the bottom of the subtitle */
1006 for( i_y = 0; i_y < i_height; i_y++,
1007 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1009 /* Draw until we reach the end of the line */
1010 for( i_x = 0; i_x < i_width; i_x++ )
1012 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1015 /* Completely transparent. Don't change pixel */
1018 else if( i_trans == MAX_TRANS ||
1019 p_filter->fmt_out.video.i_chroma ==
1020 VLC_FOURCC('R','V','1','6') )
1022 /* Completely opaque. Completely overwrite underlying pixel */
1023 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1024 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1025 if( p_filter->fmt_out.video.i_chroma !=
1026 VLC_FOURCC('R','V','1','6') )
1027 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1032 p_dst[i_x * i_pix_pitch] = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1033 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1034 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1035 p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1036 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1037 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1038 p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1039 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1040 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1053 /***********************************************************************
1055 ***********************************************************************/
1056 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1057 picture_t *p_dst_orig, picture_t *p_src,
1058 int i_x_offset, int i_y_offset,
1059 int i_width, int i_height, int i_alpha )
1061 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1062 uint8_t *p_src1_y, *p_dst_y;
1063 uint8_t *p_src1_u, *p_dst_u;
1064 uint8_t *p_src1_v, *p_dst_v;
1066 int i_x, i_y, i_trans;
1069 vlc_bool_t b_even_scanline = i_y_offset % 2;
1071 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1072 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1073 p_filter->fmt_out.video.i_x_offset +
1074 p_dst->p[Y_PLANE].i_pitch *
1075 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1076 p_dst_u = p_dst->p[U_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->p[U_PLANE].i_pitch;
1080 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1081 p_filter->fmt_out.video.i_x_offset/2 +
1082 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1083 p_dst->p[V_PLANE].i_pitch;
1085 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1086 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1087 p_filter->fmt_out.video.i_x_offset +
1088 p_dst_orig->p[Y_PLANE].i_pitch *
1089 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1090 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1091 p_filter->fmt_out.video.i_x_offset/2 +
1092 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1093 p_dst_orig->p[U_PLANE].i_pitch;
1094 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1095 p_filter->fmt_out.video.i_x_offset/2 +
1096 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1097 p_dst_orig->p[V_PLANE].i_pitch;
1099 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1100 i_src2_pitch = p_src->p->i_pitch;
1101 p_src2 = p_src->p->p_pixels +
1102 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1103 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1106 #define MAX_TRANS 255
1107 #define TRANS_BITS 8
1109 /* Draw until we reach the bottom of the subtitle */
1110 for( i_y = 0; i_y < i_height; i_y++,
1111 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1112 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1113 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1114 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1115 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1116 p_src2 += i_src2_pitch )
1118 b_even_scanline = !b_even_scanline;
1120 /* Draw until we reach the end of the line */
1121 for( i_x = 0; i_x < i_width; i_x++ )
1123 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1124 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1125 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1126 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1129 /* Completely transparent. Don't change pixel */
1132 else if( i_trans == MAX_TRANS )
1134 /* Completely opaque. Completely overwrite underlying pixel */
1135 rgb_to_yuv( &y, &u, &v, R, G, B );
1138 if( b_even_scanline && i_x % 2 == 0 )
1147 rgb_to_yuv( &y, &u, &v, R, G, B );
1148 p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1149 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1152 if( b_even_scanline && i_x % 2 == 0 )
1154 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1155 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1157 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1158 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1173 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1174 picture_t *p_dst_orig, picture_t *p_src,
1175 int i_x_offset, int i_y_offset,
1176 int i_width, int i_height, int i_alpha )
1178 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1179 uint8_t *p_dst, *p_src1, *p_src2;
1180 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1182 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1183 i_dst_pitch = p_dst_pic->p->i_pitch;
1184 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1185 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1186 p_dst_pic->p->i_pitch *
1187 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1189 i_src1_pitch = p_dst_orig->p->i_pitch;
1190 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1191 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1192 p_dst_orig->p->i_pitch *
1193 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1195 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1196 i_src2_pitch = p_src->p->i_pitch;
1197 p_src2 = p_src->p->p_pixels +
1198 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1199 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1201 #define MAX_TRANS 255
1202 #define TRANS_BITS 8
1204 /* Draw until we reach the bottom of the subtitle */
1205 for( i_y = 0; i_y < i_height; i_y++,
1206 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1208 /* Draw until we reach the end of the line */
1209 for( i_x = 0; i_x < i_width; i_x++ )
1211 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1212 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1213 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1214 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1217 /* Completely transparent. Don't change pixel */
1220 else if( i_trans == MAX_TRANS )
1222 /* Completely opaque. Completely overwrite underlying pixel */
1223 p_dst[i_x * i_pix_pitch + 0] = R;
1224 p_dst[i_x * i_pix_pitch + 1] = G;
1225 p_dst[i_x * i_pix_pitch + 2] = B;
1230 p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1231 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1232 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1233 p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1234 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1235 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1236 p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1237 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1238 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1251 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1252 picture_t *p_dst_orig, picture_t *p_src,
1253 int i_x_offset, int i_y_offset,
1254 int i_width, int i_height, int i_alpha )
1256 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1257 uint8_t *p_dst, *p_src1, *p_src2;
1258 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1261 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1262 i_dst_pitch = p_dst_pic->p->i_pitch;
1263 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1264 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1265 p_dst_pic->p->i_pitch *
1266 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1268 i_src1_pitch = p_dst_orig->p->i_pitch;
1269 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1270 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1271 p_dst_orig->p->i_pitch *
1272 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1274 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1275 i_src2_pitch = p_src->p->i_pitch;
1276 p_src2 = p_src->p->p_pixels +
1277 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1278 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1280 #define MAX_TRANS 255
1281 #define TRANS_BITS 8
1283 /* Draw until we reach the bottom of the subtitle */
1284 for( i_y = 0; i_y < i_height; i_y++,
1285 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1287 /* Draw until we reach the end of the line */
1288 for( i_x = 0; i_x < i_width; i_x++ )
1290 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1291 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1292 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1293 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1296 /* Completely transparent. Don't change pixel */
1299 else if( i_trans == MAX_TRANS )
1301 /* Completely opaque. Completely overwrite underlying pixel */
1302 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1307 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1308 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1309 ( ( ( (R >> 3)*i_trans
1310 + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1311 >> TRANS_BITS ) << 11 )
1312 | ( ( ( (G >> 2)*i_trans
1313 + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1314 >> TRANS_BITS ) << 5 )
1315 | ( ( ( (B >> 3)*i_trans
1316 + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
1330 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1331 picture_t *p_dst_orig, picture_t *p_src,
1332 int i_x_offset, int i_y_offset,
1333 int i_width, int i_height, int i_alpha )
1335 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1336 uint8_t *p_dst, *p_src1, *p_src2;
1338 int i_x, i_y, i_pix_pitch, i_trans;
1339 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1340 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1343 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1349 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1355 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1363 i_dst_pitch = p_dst_pic->p->i_pitch;
1364 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1365 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1366 p_dst_pic->p->i_pitch *
1367 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1369 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1370 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1371 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1372 p_dst_orig->p->i_pitch *
1373 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1375 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1376 i_src2_pitch = p_src->p->i_pitch;
1377 p_src2 = p_src->p->p_pixels +
1378 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1379 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1381 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1383 #define MAX_TRANS 255
1384 #define TRANS_BITS 8
1386 /* Draw until we reach the bottom of the subtitle */
1387 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
1388 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1389 p_src2 += i_src2_pitch )
1391 /* Draw until we reach the end of the line */
1392 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1394 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1395 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1396 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1397 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1400 /* Completely transparent. Don't change pixel */
1402 else if( i_trans == MAX_TRANS )
1404 /* Completely opaque. Completely overwrite underlying pixel */
1405 rgb_to_yuv( &y, &u, &v, R, G, B );
1406 p_dst[i_x * 2 + i_l_offset] = y;
1410 p_dst[i_x * 2 + i_u_offset] = u;
1411 p_dst[i_x * 2 + i_v_offset] = v;
1417 rgb_to_yuv( &y, &u, &v, R, G, B );
1418 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)y * i_trans +
1419 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
1424 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
1425 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
1427 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
1428 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )