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 */
50 /* YUVA, I420, YV12 */
51 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
52 int, int, int, int, int );
53 static void BlendI420I420( filter_t *, picture_t *, picture_t *, picture_t *,
55 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
56 int, int, int, int, int );
57 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
58 int, int, int, int, int );
59 static void BlendYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
60 int, int, int, int, int );
63 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
64 int, int, int, int, int );
65 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
66 int, int, int, int, int );
67 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
68 int, int, int, int, int );
71 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
72 int, int, int, int, int );
73 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
74 picture_t *, int, int, int, int, int );
75 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
76 int, int, int, int, int );
77 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
78 int, int, int, int, int );
80 /*****************************************************************************
82 *****************************************************************************/
84 set_description( _("Video pictures blending") );
85 set_capability( "video blending", 100 );
86 set_callbacks( OpenFilter, CloseFilter );
89 /*****************************************************************************
90 * OpenFilter: probe the filter and return score
91 *****************************************************************************/
92 static int OpenFilter( vlc_object_t *p_this )
94 filter_t *p_filter = (filter_t*)p_this;
97 /* Check if we can handle that format.
98 * We could try to use a chroma filter if we can't. */
99 int in_chroma = p_filter->fmt_in.video.i_chroma;
100 int out_chroma = p_filter->fmt_out.video.i_chroma;
101 if( ( in_chroma != VLC_FOURCC('Y','U','V','A') &&
102 in_chroma != VLC_FOURCC('I','4','2','0') &&
103 in_chroma != VLC_FOURCC('Y','V','1','2') &&
104 in_chroma != VLC_FOURCC('Y','U','V','P') &&
105 in_chroma != VLC_FOURCC('R','G','B','A') ) ||
106 ( out_chroma != VLC_FOURCC('I','4','2','0') &&
107 out_chroma != VLC_FOURCC('Y','U','Y','2') &&
108 out_chroma != VLC_FOURCC('Y','V','1','2') &&
109 out_chroma != VLC_FOURCC('U','Y','V','Y') &&
110 out_chroma != VLC_FOURCC('Y','V','Y','U') &&
111 out_chroma != VLC_FOURCC('R','V','1','6') &&
112 out_chroma != VLC_FOURCC('R','V','2','4') &&
113 out_chroma != VLC_FOURCC('R','V','3','2') ) )
118 /* Allocate the memory needed to store the decoder's structure */
119 if( ( p_filter->p_sys = p_sys =
120 (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
122 msg_Err( p_filter, "out of memory" );
127 p_filter->pf_video_blend = Blend;
129 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
130 (char *)&p_filter->fmt_in.video.i_chroma,
131 (char *)&p_filter->fmt_out.video.i_chroma );
137 /*****************************************************************************
138 * CloseFilter: clean up the filter
139 *****************************************************************************/
140 static void CloseFilter( vlc_object_t *p_this )
142 filter_t *p_filter = (filter_t*)p_this;
143 filter_sys_t *p_sys = p_filter->p_sys;
148 /****************************************************************************
149 * Blend: the whole thing
150 ****************************************************************************
151 * This function is called just after the thread is launched.
152 ****************************************************************************/
153 static void Blend( filter_t *p_filter, picture_t *p_dst,
154 picture_t *p_dst_orig, picture_t *p_src,
155 int i_x_offset, int i_y_offset, int i_alpha )
157 int i_width, i_height;
159 if( i_alpha == 0 ) return;
161 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
162 (int)p_filter->fmt_in.video.i_visible_width);
164 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
165 (int)p_filter->fmt_in.video.i_visible_height);
167 if( i_width <= 0 || i_height <= 0 ) return;
170 printf( "chroma: %4.4s -> %4.4s\n",
171 (char *)&p_filter->fmt_in.video.i_chroma,
172 (char *)&p_filter->fmt_out.video.i_chroma );
175 switch( p_filter->fmt_in.video.i_chroma )
177 case VLC_FOURCC('Y','V','1','2'):
178 case VLC_FOURCC('I','4','2','0'):
179 if( i_alpha == 0xff &&
180 ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('I','4','2','0')
181 || p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2')
184 BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
185 i_x_offset, i_y_offset,
189 case VLC_FOURCC('Y','U','V','A'):
190 switch( p_filter->fmt_out.video.i_chroma )
192 case VLC_FOURCC('I','4','2','0'):
193 case VLC_FOURCC('Y','V','1','2'):
194 BlendI420( p_filter, p_dst, p_dst_orig, p_src,
195 i_x_offset, i_y_offset,
196 i_width, i_height, i_alpha );
198 case VLC_FOURCC('Y','U','Y','2'):
199 case VLC_FOURCC('U','Y','V','Y'):
200 case VLC_FOURCC('Y','V','Y','U'):
201 BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
202 i_x_offset, i_y_offset,
203 i_width, i_height, i_alpha );
205 case VLC_FOURCC('R','V','1','6'):
206 BlendR16( p_filter, p_dst, p_dst_orig, p_src,
207 i_x_offset, i_y_offset,
208 i_width, i_height, i_alpha );
210 case VLC_FOURCC('R','V','2','4'):
211 case VLC_FOURCC('R','V','3','2'):
212 BlendR24( p_filter, p_dst, p_dst_orig, p_src,
213 i_x_offset, i_y_offset,
214 i_width, i_height, i_alpha );
217 case VLC_FOURCC('Y','U','V','P'):
218 switch( p_filter->fmt_out.video.i_chroma )
220 case VLC_FOURCC('I','4','2','0'):
221 case VLC_FOURCC('Y','V','1','2'):
222 BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
223 i_x_offset, i_y_offset,
224 i_width, i_height, i_alpha );
226 case VLC_FOURCC('Y','U','Y','2'):
227 case VLC_FOURCC('U','Y','V','Y'):
228 case VLC_FOURCC('Y','V','Y','U'):
229 BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
230 i_x_offset, i_y_offset,
231 i_width, i_height, i_alpha );
233 case VLC_FOURCC('R','V','1','6'):
234 case VLC_FOURCC('R','V','2','4'):
235 case VLC_FOURCC('R','V','3','2'):
236 BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
237 i_x_offset, i_y_offset,
238 i_width, i_height, i_alpha );
241 case VLC_FOURCC('R','G','B','A'):
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 BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
247 i_x_offset, i_y_offset,
248 i_width, i_height, i_alpha );
250 case VLC_FOURCC('Y','U','Y','2'):
251 case VLC_FOURCC('U','Y','V','Y'):
252 case VLC_FOURCC('Y','V','Y','U'):
253 BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
254 i_x_offset, i_y_offset,
255 i_width, i_height, i_alpha );
257 case VLC_FOURCC('R','V','2','4'):
258 case VLC_FOURCC('R','V','3','2'):
259 BlendRGBAR24( 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 BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
265 i_x_offset, i_y_offset,
266 i_width, i_height, i_alpha );
271 msg_Dbg( p_filter, "no matching alpha blending routine "
272 "(chroma: %4.4s -> %4.4s)",
273 (char *)&p_filter->fmt_in.video.i_chroma,
274 (char *)&p_filter->fmt_out.video.i_chroma );
277 /***********************************************************************
279 ***********************************************************************/
280 static inline void yuv_to_rgb( int *r, int *g, int *b,
281 uint8_t y1, uint8_t u1, uint8_t v1 )
283 /* macros used for YUV pixel conversions */
284 # define SCALEBITS 10
285 # define ONE_HALF (1 << (SCALEBITS - 1))
286 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
287 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
289 int y, cb, cr, r_add, g_add, b_add;
293 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
294 g_add = - FIX(0.34414*255.0/224.0) * cb
295 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
296 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
297 y = (y1 - 16) * FIX(255.0/219.0);
298 *r = CLAMP((y + r_add) >> SCALEBITS);
299 *g = CLAMP((y + g_add) >> SCALEBITS);
300 *b = CLAMP((y + b_add) >> SCALEBITS);
303 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
304 int r, int g, int b )
306 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
307 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
308 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
311 /***********************************************************************
313 ***********************************************************************/
314 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
315 picture_t *p_dst_orig, picture_t *p_src,
316 int i_x_offset, int i_y_offset,
317 int i_width, int i_height, int i_alpha )
319 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
320 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
321 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
322 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
324 int i_x, i_y, i_trans = 0;
325 vlc_bool_t b_even_scanline = i_y_offset % 2;
327 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
328 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
329 p_filter->fmt_out.video.i_x_offset +
330 p_dst->p[Y_PLANE].i_pitch *
331 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
332 p_dst_u = p_dst->p[U_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->p[U_PLANE].i_pitch;
336 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
337 p_filter->fmt_out.video.i_x_offset/2 +
338 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
339 p_dst->p[V_PLANE].i_pitch;
341 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
342 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
343 p_filter->fmt_out.video.i_x_offset +
344 p_dst_orig->p[Y_PLANE].i_pitch *
345 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
346 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
347 p_filter->fmt_out.video.i_x_offset/2 +
348 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
349 p_dst_orig->p[U_PLANE].i_pitch;
350 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
351 p_filter->fmt_out.video.i_x_offset/2 +
352 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
353 p_dst_orig->p[V_PLANE].i_pitch;
355 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
356 p_src2_y = p_src->p[Y_PLANE].p_pixels +
357 p_filter->fmt_in.video.i_x_offset +
358 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
359 p_src2_u = p_src->p[U_PLANE].p_pixels +
360 p_filter->fmt_in.video.i_x_offset/2 +
361 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
362 p_src2_v = p_src->p[V_PLANE].p_pixels +
363 p_filter->fmt_in.video.i_x_offset/2 +
364 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
366 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
367 p_filter->fmt_in.video.i_chroma == VLC_FOURCC('I','4','2','0') )
374 p_trans = p_src->p[A_PLANE].p_pixels +
375 p_filter->fmt_in.video.i_x_offset +
376 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
379 #define MAX_TRANS 255
382 /* Draw until we reach the bottom of the subtitle */
383 for( i_y = 0; i_y < i_height; i_y++, p_trans += p_trans?i_src2_pitch:0,
384 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
385 p_src2_y += i_src2_pitch,
386 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
387 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
388 p_src2_u += i_src2_pitch,
389 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
390 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
391 p_src2_v += i_src2_pitch )
393 b_even_scanline = !b_even_scanline;
395 /* Draw until we reach the end of the line */
396 for( i_x = 0; i_x < i_width; i_x++ )
399 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
402 /* Completely transparent. Don't change pixel */
405 else if( i_trans == MAX_TRANS )
407 /* Completely opaque. Completely overwrite underlying pixel */
408 p_dst_y[i_x] = p_src2_y[i_x];
410 if( b_even_scanline && i_x % 2 == 0 )
412 p_dst_u[i_x/2] = p_src2_u[i_x];
413 p_dst_v[i_x/2] = p_src2_v[i_x];
419 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
420 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
423 if( b_even_scanline && i_x % 2 == 0 )
425 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
426 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
428 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
429 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
440 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
441 picture_t *p_dst_orig, picture_t *p_src,
442 int i_x_offset, int i_y_offset,
443 int i_width, int i_height )
445 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
446 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
447 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
448 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
450 vlc_bool_t b_even_scanline = i_y_offset % 2;
452 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
453 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
454 p_filter->fmt_out.video.i_x_offset +
455 p_dst->p[Y_PLANE].i_pitch *
456 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
457 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
458 p_filter->fmt_out.video.i_x_offset/2 +
459 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
460 p_dst->p[U_PLANE].i_pitch;
461 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
462 p_filter->fmt_out.video.i_x_offset/2 +
463 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
464 p_dst->p[V_PLANE].i_pitch;
466 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
467 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
468 p_filter->fmt_out.video.i_x_offset +
469 p_dst_orig->p[Y_PLANE].i_pitch *
470 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
471 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
472 p_filter->fmt_out.video.i_x_offset/2 +
473 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
474 p_dst_orig->p[U_PLANE].i_pitch;
475 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
476 p_filter->fmt_out.video.i_x_offset/2 +
477 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
478 p_dst_orig->p[V_PLANE].i_pitch;
480 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
481 p_src2_y = p_src->p[Y_PLANE].p_pixels +
482 p_filter->fmt_in.video.i_x_offset +
483 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
484 p_src2_u = p_src->p[U_PLANE].p_pixels +
485 p_filter->fmt_in.video.i_x_offset/2 +
486 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
487 p_src2_v = p_src->p[V_PLANE].p_pixels +
488 p_filter->fmt_in.video.i_x_offset/2 +
489 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
493 /* Draw until we reach the bottom of the subtitle */
494 for( i_y = 0; i_y < i_height; i_y++,
495 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
496 p_src2_y += i_src2_pitch,
497 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
498 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
499 p_src2_u += i_src2_pitch,
500 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
501 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
502 p_src2_v += i_src2_pitch )
504 b_even_scanline = !b_even_scanline;
506 /* Completely opaque. Completely overwrite underlying pixel */
507 p_filter->p_libvlc->pf_memcpy( p_dst_y, p_src2_y, i_width );
509 if( b_even_scanline )
511 p_filter->p_libvlc->pf_memcpy( p_dst_u, p_src2_u, i_width/2 );
512 p_filter->p_libvlc->pf_memcpy( p_dst_y, p_src2_y, i_width/2 );
519 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
520 picture_t *p_dst_orig, picture_t *p_src,
521 int i_x_offset, int i_y_offset,
522 int i_width, int i_height, int i_alpha )
524 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
525 uint8_t *p_dst, *p_src1, *p_src2_y;
526 uint8_t *p_src2_u, *p_src2_v;
528 int i_x, i_y, i_pix_pitch, i_trans = 0;
531 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
532 i_dst_pitch = p_dst_pic->p->i_pitch;
533 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
534 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
535 p_dst_pic->p->i_pitch *
536 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
538 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
539 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
540 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
541 p_dst_orig->p->i_pitch *
542 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
544 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
545 p_src2_y = p_src->p[Y_PLANE].p_pixels +
546 p_filter->fmt_in.video.i_x_offset +
547 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
548 p_src2_u = p_src->p[U_PLANE].p_pixels +
549 p_filter->fmt_in.video.i_x_offset/2 +
550 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
551 p_src2_v = p_src->p[V_PLANE].p_pixels +
552 p_filter->fmt_in.video.i_x_offset/2 +
553 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
555 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
556 p_filter->fmt_in.video.i_chroma == VLC_FOURCC('I','4','2','0') )
563 p_trans = p_src->p[A_PLANE].p_pixels +
564 p_filter->fmt_in.video.i_x_offset +
565 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
568 #define MAX_TRANS 255
571 /* Draw until we reach the bottom of the subtitle */
572 for( i_y = 0; i_y < i_height; i_y++, p_trans += p_trans?i_src2_pitch:0,
573 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
574 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
575 p_src2_v += i_src2_pitch )
577 /* Draw until we reach the end of the line */
578 for( i_x = 0; i_x < i_width; i_x++ )
581 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
584 /* Completely transparent. Don't change pixel */
587 else if( i_trans == MAX_TRANS )
589 /* Completely opaque. Completely overwrite underlying pixel */
590 yuv_to_rgb( &r, &g, &b,
591 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
593 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
598 /* FIXME: do the blending */
599 yuv_to_rgb( &r, &g, &b,
600 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
602 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
612 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
613 picture_t *p_dst_orig, picture_t *p_src,
614 int i_x_offset, int i_y_offset,
615 int i_width, int i_height, int i_alpha )
617 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
618 uint8_t *p_dst, *p_src1, *p_src2_y;
619 uint8_t *p_src2_u, *p_src2_v;
621 int i_x, i_y, i_pix_pitch, i_trans = 0;
624 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
625 i_dst_pitch = p_dst_pic->p->i_pitch;
626 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
627 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
628 p_dst_pic->p->i_pitch *
629 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
631 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
632 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
633 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
634 p_dst_orig->p->i_pitch *
635 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
637 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
638 p_src2_y = p_src->p[Y_PLANE].p_pixels +
639 p_filter->fmt_in.video.i_x_offset +
640 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
641 p_src2_u = p_src->p[U_PLANE].p_pixels +
642 p_filter->fmt_in.video.i_x_offset/2 +
643 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
644 p_src2_v = p_src->p[V_PLANE].p_pixels +
645 p_filter->fmt_in.video.i_x_offset/2 +
646 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
648 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
649 p_filter->fmt_in.video.i_chroma == VLC_FOURCC('I','4','2','0') )
656 p_trans = p_src->p[A_PLANE].p_pixels +
657 p_filter->fmt_in.video.i_x_offset +
658 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
661 #define MAX_TRANS 255
664 /* Draw until we reach the bottom of the subtitle */
665 for( i_y = 0; i_y < i_height; i_y++, p_trans += p_trans?i_src2_pitch:0,
666 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
667 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
668 p_src2_v += i_src2_pitch )
670 /* Draw until we reach the end of the line */
671 for( i_x = 0; i_x < i_width; i_x++ )
674 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
677 /* Completely transparent. Don't change pixel */
680 else if( i_trans == MAX_TRANS )
682 /* Completely opaque. Completely overwrite underlying pixel */
683 yuv_to_rgb( &r, &g, &b,
684 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
686 p_dst[i_x * i_pix_pitch] = r;
687 p_dst[i_x * i_pix_pitch + 1] = g;
688 p_dst[i_x * i_pix_pitch + 2] = b;
693 yuv_to_rgb( &r, &g, &b,
694 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
696 p_dst[i_x * i_pix_pitch] = ( r * i_trans +
697 (uint16_t)p_src1[i_x * i_pix_pitch] *
698 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
699 p_dst[i_x * i_pix_pitch + 1] = ( g * i_trans +
700 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
701 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
702 p_dst[i_x * i_pix_pitch + 2] = ( b * i_trans +
703 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
704 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
714 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
715 picture_t *p_dst_orig, picture_t *p_src,
716 int i_x_offset, int i_y_offset,
717 int i_width, int i_height, int i_alpha )
719 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
720 uint8_t *p_dst, *p_src1, *p_src2_y;
721 uint8_t *p_src2_u, *p_src2_v;
723 int i_x, i_y, i_pix_pitch, i_trans = 0;
724 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
725 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
727 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
733 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
739 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
747 i_dst_pitch = p_dst_pic->p->i_pitch;
748 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
749 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
750 p_dst_pic->p->i_pitch *
751 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
753 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
754 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
755 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
756 p_dst_orig->p->i_pitch *
757 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
759 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
760 p_src2_y = p_src->p[Y_PLANE].p_pixels +
761 p_filter->fmt_in.video.i_x_offset +
762 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
763 p_src2_u = p_src->p[U_PLANE].p_pixels +
764 p_filter->fmt_in.video.i_x_offset/2 +
765 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
766 p_src2_v = p_src->p[V_PLANE].p_pixels +
767 p_filter->fmt_in.video.i_x_offset/2 +
768 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
770 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
771 p_filter->fmt_in.video.i_chroma == VLC_FOURCC('I','4','2','0') )
778 p_trans = p_src->p[A_PLANE].p_pixels +
779 p_filter->fmt_in.video.i_x_offset +
780 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
783 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
785 #define MAX_TRANS 255
788 /* Draw until we reach the bottom of the subtitle */
789 for( i_y = 0; i_y < i_height; i_y++, p_trans += p_trans?i_src2_pitch:0,
790 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
791 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
792 p_src2_v += i_src2_pitch )
794 /* Draw until we reach the end of the line */
795 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
798 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
801 /* Completely transparent. Don't change pixel */
803 else if( i_trans == MAX_TRANS )
805 /* Completely opaque. Completely overwrite underlying pixel */
806 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
810 if( p_trans[i_x+1] > 0xaa )
812 p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
813 p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
817 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
818 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
825 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_trans +
826 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
833 if( p_trans[i_x+1] > 0xaa )
835 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
836 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
843 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
844 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
846 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
847 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
860 /***********************************************************************
862 ***********************************************************************/
863 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
864 picture_t *p_dst_orig, picture_t *p_src,
865 int i_x_offset, int i_y_offset,
866 int i_width, int i_height, int i_alpha )
868 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
869 uint8_t *p_src1_y, *p_src2, *p_dst_y;
870 uint8_t *p_src1_u, *p_dst_u;
871 uint8_t *p_src1_v, *p_dst_v;
872 int i_x, i_y, i_trans;
873 vlc_bool_t b_even_scanline = i_y_offset % 2;
875 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
876 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
877 p_filter->fmt_out.video.i_x_offset +
878 p_dst->p[Y_PLANE].i_pitch *
879 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
880 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
881 p_filter->fmt_out.video.i_x_offset/2 +
882 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
883 p_dst->p[U_PLANE].i_pitch;
884 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
885 p_filter->fmt_out.video.i_x_offset/2 +
886 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
887 p_dst->p[V_PLANE].i_pitch;
889 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
890 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
891 p_filter->fmt_out.video.i_x_offset +
892 p_dst_orig->p[Y_PLANE].i_pitch *
893 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
894 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
895 p_filter->fmt_out.video.i_x_offset/2 +
896 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
897 p_dst_orig->p[U_PLANE].i_pitch;
898 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
899 p_filter->fmt_out.video.i_x_offset/2 +
900 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
901 p_dst_orig->p[V_PLANE].i_pitch;
903 i_src2_pitch = p_src->p->i_pitch;
904 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
905 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
907 #define MAX_TRANS 255
909 #define p_trans p_src2
910 #define p_pal p_filter->fmt_in.video.p_palette->palette
912 /* Draw until we reach the bottom of the subtitle */
913 for( i_y = 0; i_y < i_height; i_y++,
914 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
915 p_src2 += i_src2_pitch,
916 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
917 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
918 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
919 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
921 b_even_scanline = !b_even_scanline;
923 /* Draw until we reach the end of the line */
924 for( i_x = 0; i_x < i_width; i_x++ )
926 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
929 /* Completely transparent. Don't change pixel */
932 else if( i_trans == MAX_TRANS )
934 /* Completely opaque. Completely overwrite underlying pixel */
935 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
937 if( b_even_scanline && i_x % 2 == 0 )
939 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
940 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
946 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
947 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
950 if( b_even_scanline && i_x % 2 == 0 )
952 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
953 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
955 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
956 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
970 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
971 picture_t *p_dst_orig, picture_t *p_src,
972 int i_x_offset, int i_y_offset,
973 int i_width, int i_height, int i_alpha )
975 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
976 uint8_t *p_src1, *p_src2, *p_dst;
977 int i_x, i_y, i_pix_pitch, i_trans;
978 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
979 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
981 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
987 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
993 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1001 i_dst_pitch = p_dst_pic->p->i_pitch;
1002 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1003 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1004 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1006 i_src1_pitch = p_dst_orig->p->i_pitch;
1007 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1008 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1009 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1011 i_src2_pitch = p_src->p->i_pitch;
1012 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1013 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1015 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1017 #define MAX_TRANS 255
1018 #define TRANS_BITS 8
1019 #define p_trans p_src2
1020 #define p_pal p_filter->fmt_in.video.p_palette->palette
1022 /* Draw until we reach the bottom of the subtitle */
1023 for( i_y = 0; i_y < i_height; i_y++,
1024 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1026 /* Draw until we reach the end of the line */
1027 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1029 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1032 /* Completely transparent. Don't change pixel */
1034 else if( i_trans == MAX_TRANS )
1036 /* Completely opaque. Completely overwrite underlying pixel */
1037 p_dst[i_x * 2 + i_l_offset] = p_pal[p_src2[i_x]][0];
1041 if( p_trans[i_x+1] > 0xaa )
1043 p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1044 p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1048 p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1049 p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1056 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1057 i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1058 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1064 if( p_trans[i_x+1] > 0xaa )
1066 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1067 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1071 i_u = p_pal[p_src2[i_x]][1];
1072 i_v = p_pal[p_src2[i_x]][2];
1075 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1076 i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1077 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1078 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1079 i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1080 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1094 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1095 picture_t *p_dst_orig, picture_t *p_src,
1096 int i_x_offset, int i_y_offset,
1097 int i_width, int i_height, int i_alpha )
1099 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1100 uint8_t *p_src1, *p_src2, *p_dst;
1101 int i_x, i_y, i_pix_pitch, i_trans;
1103 video_palette_t rgbpalette;
1105 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1106 i_dst_pitch = p_dst_pic->p->i_pitch;
1107 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1108 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1109 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1111 i_src1_pitch = p_dst_orig->p->i_pitch;
1112 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1113 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1114 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1116 i_src2_pitch = p_src->p->i_pitch;
1117 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1118 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1120 #define MAX_TRANS 255
1121 #define TRANS_BITS 8
1122 #define p_trans p_src2
1123 #define p_pal p_filter->fmt_in.video.p_palette->palette
1124 #define rgbpal rgbpalette.palette
1126 /* Convert palette first */
1127 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1130 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1132 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1134 *(uint16_t *)rgbpal[i_y] =
1135 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1139 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1143 /* Draw until we reach the bottom of the subtitle */
1144 for( i_y = 0; i_y < i_height; i_y++,
1145 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1147 /* Draw until we reach the end of the line */
1148 for( i_x = 0; i_x < i_width; i_x++ )
1150 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1153 /* Completely transparent. Don't change pixel */
1156 else if( i_trans == MAX_TRANS ||
1157 p_filter->fmt_out.video.i_chroma ==
1158 VLC_FOURCC('R','V','1','6') )
1160 /* Completely opaque. Completely overwrite underlying pixel */
1161 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1162 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1163 if( p_filter->fmt_out.video.i_chroma !=
1164 VLC_FOURCC('R','V','1','6') )
1165 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1170 p_dst[i_x * i_pix_pitch] = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1171 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1172 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1173 p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1174 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1175 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1176 p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1177 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1178 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1191 /***********************************************************************
1193 ***********************************************************************/
1194 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1195 picture_t *p_dst_orig, picture_t *p_src,
1196 int i_x_offset, int i_y_offset,
1197 int i_width, int i_height, int i_alpha )
1199 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1200 uint8_t *p_src1_y, *p_dst_y;
1201 uint8_t *p_src1_u, *p_dst_u;
1202 uint8_t *p_src1_v, *p_dst_v;
1204 int i_x, i_y, i_trans;
1207 vlc_bool_t b_even_scanline = i_y_offset % 2;
1209 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1210 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1211 p_filter->fmt_out.video.i_x_offset +
1212 p_dst->p[Y_PLANE].i_pitch *
1213 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1214 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1215 p_filter->fmt_out.video.i_x_offset/2 +
1216 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1217 p_dst->p[U_PLANE].i_pitch;
1218 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1219 p_filter->fmt_out.video.i_x_offset/2 +
1220 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1221 p_dst->p[V_PLANE].i_pitch;
1223 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1224 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1225 p_filter->fmt_out.video.i_x_offset +
1226 p_dst_orig->p[Y_PLANE].i_pitch *
1227 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1228 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1229 p_filter->fmt_out.video.i_x_offset/2 +
1230 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1231 p_dst_orig->p[U_PLANE].i_pitch;
1232 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1233 p_filter->fmt_out.video.i_x_offset/2 +
1234 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1235 p_dst_orig->p[V_PLANE].i_pitch;
1237 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1238 i_src2_pitch = p_src->p->i_pitch;
1239 p_src2 = p_src->p->p_pixels +
1240 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1241 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1244 #define MAX_TRANS 255
1245 #define TRANS_BITS 8
1247 /* Draw until we reach the bottom of the subtitle */
1248 for( i_y = 0; i_y < i_height; i_y++,
1249 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1250 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1251 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1252 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1253 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1254 p_src2 += i_src2_pitch )
1256 b_even_scanline = !b_even_scanline;
1258 /* Draw until we reach the end of the line */
1259 for( i_x = 0; i_x < i_width; i_x++ )
1261 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1262 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1263 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1264 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1267 /* Completely transparent. Don't change pixel */
1270 else if( i_trans == MAX_TRANS )
1272 /* Completely opaque. Completely overwrite underlying pixel */
1273 rgb_to_yuv( &y, &u, &v, R, G, B );
1276 if( b_even_scanline && i_x % 2 == 0 )
1285 rgb_to_yuv( &y, &u, &v, R, G, B );
1286 p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1287 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1290 if( b_even_scanline && i_x % 2 == 0 )
1292 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1293 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1295 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1296 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1311 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1312 picture_t *p_dst_orig, picture_t *p_src,
1313 int i_x_offset, int i_y_offset,
1314 int i_width, int i_height, int i_alpha )
1316 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1317 uint8_t *p_dst, *p_src1, *p_src2;
1318 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1320 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1321 i_dst_pitch = p_dst_pic->p->i_pitch;
1322 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1323 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1324 p_dst_pic->p->i_pitch *
1325 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1327 i_src1_pitch = p_dst_orig->p->i_pitch;
1328 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1329 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1330 p_dst_orig->p->i_pitch *
1331 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1333 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1334 i_src2_pitch = p_src->p->i_pitch;
1335 p_src2 = p_src->p->p_pixels +
1336 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1337 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1339 #define MAX_TRANS 255
1340 #define TRANS_BITS 8
1342 /* Draw until we reach the bottom of the subtitle */
1343 for( i_y = 0; i_y < i_height; i_y++,
1344 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1346 /* Draw until we reach the end of the line */
1347 for( i_x = 0; i_x < i_width; i_x++ )
1349 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1350 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1351 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1352 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1355 /* Completely transparent. Don't change pixel */
1358 else if( i_trans == MAX_TRANS )
1360 /* Completely opaque. Completely overwrite underlying pixel */
1361 p_dst[i_x * i_pix_pitch + 0] = R;
1362 p_dst[i_x * i_pix_pitch + 1] = G;
1363 p_dst[i_x * i_pix_pitch + 2] = B;
1368 p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1369 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1370 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1371 p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1372 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1373 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1374 p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1375 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1376 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1389 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1390 picture_t *p_dst_orig, picture_t *p_src,
1391 int i_x_offset, int i_y_offset,
1392 int i_width, int i_height, int i_alpha )
1394 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1395 uint8_t *p_dst, *p_src1, *p_src2;
1396 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1399 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1400 i_dst_pitch = p_dst_pic->p->i_pitch;
1401 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1402 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1403 p_dst_pic->p->i_pitch *
1404 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1406 i_src1_pitch = p_dst_orig->p->i_pitch;
1407 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1408 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1409 p_dst_orig->p->i_pitch *
1410 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1412 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1413 i_src2_pitch = p_src->p->i_pitch;
1414 p_src2 = p_src->p->p_pixels +
1415 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1416 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1418 #define MAX_TRANS 255
1419 #define TRANS_BITS 8
1421 /* Draw until we reach the bottom of the subtitle */
1422 for( i_y = 0; i_y < i_height; i_y++,
1423 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1425 /* Draw until we reach the end of the line */
1426 for( i_x = 0; i_x < i_width; i_x++ )
1428 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1429 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1430 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1431 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1434 /* Completely transparent. Don't change pixel */
1437 else if( i_trans == MAX_TRANS )
1439 /* Completely opaque. Completely overwrite underlying pixel */
1440 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1445 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1446 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1447 ( ( ( (R >> 3)*i_trans
1448 + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1449 >> TRANS_BITS ) << 11 )
1450 | ( ( ( (G >> 2)*i_trans
1451 + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1452 >> TRANS_BITS ) << 5 )
1453 | ( ( ( (B >> 3)*i_trans
1454 + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
1468 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1469 picture_t *p_dst_orig, picture_t *p_src,
1470 int i_x_offset, int i_y_offset,
1471 int i_width, int i_height, int i_alpha )
1473 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1474 uint8_t *p_dst, *p_src1, *p_src2;
1476 int i_x, i_y, i_pix_pitch, i_trans;
1477 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1478 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1481 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1487 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1493 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1501 i_dst_pitch = p_dst_pic->p->i_pitch;
1502 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1503 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1504 p_dst_pic->p->i_pitch *
1505 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1507 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1508 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1509 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1510 p_dst_orig->p->i_pitch *
1511 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1513 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1514 i_src2_pitch = p_src->p->i_pitch;
1515 p_src2 = p_src->p->p_pixels +
1516 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1517 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1519 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1521 #define MAX_TRANS 255
1522 #define TRANS_BITS 8
1524 /* Draw until we reach the bottom of the subtitle */
1525 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
1526 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1527 p_src2 += i_src2_pitch )
1529 /* Draw until we reach the end of the line */
1530 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1532 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1533 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1534 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1535 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1538 /* Completely transparent. Don't change pixel */
1540 else if( i_trans == MAX_TRANS )
1542 /* Completely opaque. Completely overwrite underlying pixel */
1543 rgb_to_yuv( &y, &u, &v, R, G, B );
1544 p_dst[i_x * 2 + i_l_offset] = y;
1548 p_dst[i_x * 2 + i_u_offset] = u;
1549 p_dst[i_x * 2 + i_v_offset] = v;
1555 rgb_to_yuv( &y, &u, &v, R, G, B );
1556 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)y * i_trans +
1557 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
1562 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
1563 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
1565 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
1566 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )