1 /*****************************************************************************
2 * blend.c: alpha blend 2 pictures together
3 *****************************************************************************
4 * Copyright (C) 2003-2007 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
8 * Antoine Cellerier <dionoea @t videolan dot org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include "vlc_filter.h"
37 /*****************************************************************************
38 * filter_sys_t : filter descriptor
39 *****************************************************************************/
45 /****************************************************************************
47 ****************************************************************************/
48 static int OpenFilter ( vlc_object_t * );
49 static void CloseFilter( vlc_object_t * );
51 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
54 /* TODO i_alpha support for BlendR16 */
56 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
57 int, int, int, int, int );
58 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
59 int, int, int, int, int );
60 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
61 int, int, int, int, int );
62 static void BlendYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
63 int, int, int, int, int );
66 static void BlendI420I420( filter_t *, picture_t *, picture_t *, picture_t *,
67 int, int, int, int, int );
68 static void BlendI420I420_no_alpha(
69 filter_t *, picture_t *, picture_t *, picture_t *,
71 static void BlendI420R16( filter_t *, picture_t *, picture_t *, picture_t *,
72 int, int, int, int, int );
73 static void BlendI420R24( filter_t *, picture_t *, picture_t *, picture_t *,
74 int, int, int, int, int );
75 static void BlendI420YUVPacked( filter_t *, picture_t *, picture_t *,
76 picture_t *, int, int, int, int, int );
79 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
80 int, int, int, int, int );
81 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
82 int, int, int, int, int );
83 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
84 int, int, int, int, int );
87 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
88 int, int, int, int, int );
89 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
90 picture_t *, int, int, int, int, int );
91 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
92 int, int, int, int, int );
93 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
94 int, int, int, int, int );
96 /*****************************************************************************
98 *****************************************************************************/
100 set_description( N_("Video pictures blending") );
101 set_capability( "video blending", 100 );
102 set_callbacks( OpenFilter, CloseFilter );
105 /*****************************************************************************
106 * OpenFilter: probe the filter and return score
107 *****************************************************************************/
108 static int OpenFilter( vlc_object_t *p_this )
110 filter_t *p_filter = (filter_t*)p_this;
113 /* Check if we can handle that format.
114 * We could try to use a chroma filter if we can't. */
115 int in_chroma = p_filter->fmt_in.video.i_chroma;
116 int out_chroma = p_filter->fmt_out.video.i_chroma;
117 if( ( in_chroma != VLC_FOURCC('Y','U','V','A') &&
118 in_chroma != VLC_FOURCC('I','4','2','0') &&
119 in_chroma != VLC_FOURCC('Y','V','1','2') &&
120 in_chroma != VLC_FOURCC('Y','U','V','P') &&
121 in_chroma != VLC_FOURCC('R','G','B','A') ) ||
122 ( out_chroma != VLC_FOURCC('I','4','2','0') &&
123 out_chroma != VLC_FOURCC('Y','U','Y','2') &&
124 out_chroma != VLC_FOURCC('Y','V','1','2') &&
125 out_chroma != VLC_FOURCC('U','Y','V','Y') &&
126 out_chroma != VLC_FOURCC('Y','V','Y','U') &&
127 out_chroma != VLC_FOURCC('R','V','1','6') &&
128 out_chroma != VLC_FOURCC('R','V','2','4') &&
129 out_chroma != VLC_FOURCC('R','V','3','2') ) )
134 /* Allocate the memory needed to store the decoder's structure */
135 if( ( p_filter->p_sys = p_sys =
136 (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
138 msg_Err( p_filter, "out of memory" );
143 p_filter->pf_video_blend = Blend;
145 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
146 (char *)&p_filter->fmt_in.video.i_chroma,
147 (char *)&p_filter->fmt_out.video.i_chroma );
152 /*****************************************************************************
153 * CloseFilter: clean up the filter
154 *****************************************************************************/
155 static void CloseFilter( vlc_object_t *p_this )
157 filter_t *p_filter = (filter_t*)p_this;
158 filter_sys_t *p_sys = p_filter->p_sys;
163 /****************************************************************************
164 * Blend: the whole thing
165 ****************************************************************************
166 * This function is called just after the thread is launched.
167 ****************************************************************************/
168 static void Blend( filter_t *p_filter, picture_t *p_dst,
169 picture_t *p_dst_orig, picture_t *p_src,
170 int i_x_offset, int i_y_offset, int i_alpha )
172 int i_width, i_height;
174 if( i_alpha == 0 ) return;
176 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
177 (int)p_filter->fmt_in.video.i_visible_width);
179 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
180 (int)p_filter->fmt_in.video.i_visible_height);
182 if( i_width <= 0 || i_height <= 0 ) return;
185 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
186 (char *)&p_filter->fmt_in.video.i_chroma,
187 (char *)&p_filter->fmt_out.video.i_chroma );
190 switch( p_filter->fmt_in.video.i_chroma )
192 case VLC_FOURCC('Y','U','V','A'):
193 switch( p_filter->fmt_out.video.i_chroma )
195 case VLC_FOURCC('I','4','2','0'):
196 case VLC_FOURCC('Y','V','1','2'):
197 BlendI420( p_filter, p_dst, p_dst_orig, p_src,
198 i_x_offset, i_y_offset,
199 i_width, i_height, i_alpha );
201 case VLC_FOURCC('Y','U','Y','2'):
202 case VLC_FOURCC('U','Y','V','Y'):
203 case VLC_FOURCC('Y','V','Y','U'):
204 BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
205 i_x_offset, i_y_offset,
206 i_width, i_height, i_alpha );
208 case VLC_FOURCC('R','V','1','6'):
209 BlendR16( p_filter, p_dst, p_dst_orig, p_src,
210 i_x_offset, i_y_offset,
211 i_width, i_height, i_alpha );
213 case VLC_FOURCC('R','V','2','4'):
214 case VLC_FOURCC('R','V','3','2'):
215 BlendR24( p_filter, p_dst, p_dst_orig, p_src,
216 i_x_offset, i_y_offset,
217 i_width, i_height, i_alpha );
220 case VLC_FOURCC('Y','U','V','P'):
221 switch( p_filter->fmt_out.video.i_chroma )
223 case VLC_FOURCC('I','4','2','0'):
224 case VLC_FOURCC('Y','V','1','2'):
225 BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
226 i_x_offset, i_y_offset,
227 i_width, i_height, i_alpha );
229 case VLC_FOURCC('Y','U','Y','2'):
230 case VLC_FOURCC('U','Y','V','Y'):
231 case VLC_FOURCC('Y','V','Y','U'):
232 BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
233 i_x_offset, i_y_offset,
234 i_width, i_height, i_alpha );
236 case VLC_FOURCC('R','V','1','6'):
237 case VLC_FOURCC('R','V','2','4'):
238 case VLC_FOURCC('R','V','3','2'):
239 BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
240 i_x_offset, i_y_offset,
241 i_width, i_height, i_alpha );
244 case VLC_FOURCC('Y','V','1','2'):
245 case VLC_FOURCC('I','4','2','0'):
246 switch( p_filter->fmt_out.video.i_chroma )
248 case VLC_FOURCC('I','4','2','0'):
249 case VLC_FOURCC('Y','V','1','2'):
250 if( i_alpha == 0xff )
251 BlendI420I420_no_alpha(
252 p_filter, p_dst, p_dst_orig, p_src,
253 i_x_offset, i_y_offset,
256 BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
257 i_x_offset, i_y_offset,
258 i_width, i_height, i_alpha );
260 case VLC_FOURCC('Y','U','Y','2'):
261 case VLC_FOURCC('U','Y','V','Y'):
262 case VLC_FOURCC('Y','V','Y','U'):
263 BlendI420YUVPacked( p_filter, p_dst, p_dst_orig, p_src,
264 i_x_offset, i_y_offset,
265 i_width, i_height, i_alpha );
267 case VLC_FOURCC('R','V','1','6'):
268 BlendI420R16( p_filter, p_dst, p_dst_orig, p_src,
269 i_x_offset, i_y_offset,
270 i_width, i_height, i_alpha );
272 case VLC_FOURCC('R','V','2','4'):
273 case VLC_FOURCC('R','V','3','2'):
274 BlendI420R24( p_filter, p_dst, p_dst_orig, p_src,
275 i_x_offset, i_y_offset,
276 i_width, i_height, i_alpha );
279 case VLC_FOURCC('R','G','B','A'):
280 switch( p_filter->fmt_out.video.i_chroma )
282 case VLC_FOURCC('I','4','2','0'):
283 case VLC_FOURCC('Y','V','1','2'):
284 BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
285 i_x_offset, i_y_offset,
286 i_width, i_height, i_alpha );
288 case VLC_FOURCC('Y','U','Y','2'):
289 case VLC_FOURCC('U','Y','V','Y'):
290 case VLC_FOURCC('Y','V','Y','U'):
291 BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
292 i_x_offset, i_y_offset,
293 i_width, i_height, i_alpha );
295 case VLC_FOURCC('R','V','2','4'):
296 case VLC_FOURCC('R','V','3','2'):
297 BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
298 i_x_offset, i_y_offset,
299 i_width, i_height, i_alpha );
301 case VLC_FOURCC('R','V','1','6'):
302 BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
303 i_x_offset, i_y_offset,
304 i_width, i_height, i_alpha );
309 msg_Dbg( p_filter, "no matching alpha blending routine "
310 "(chroma: %4.4s -> %4.4s)",
311 (char *)&p_filter->fmt_in.video.i_chroma,
312 (char *)&p_filter->fmt_out.video.i_chroma );
315 /***********************************************************************
317 ***********************************************************************/
318 static inline void yuv_to_rgb( int *r, int *g, int *b,
319 uint8_t y1, uint8_t u1, uint8_t v1 )
321 /* macros used for YUV pixel conversions */
322 # define SCALEBITS 10
323 # define ONE_HALF (1 << (SCALEBITS - 1))
324 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
325 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
327 int y, cb, cr, r_add, g_add, b_add;
331 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
332 g_add = - FIX(0.34414*255.0/224.0) * cb
333 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
334 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
335 y = (y1 - 16) * FIX(255.0/219.0);
336 *r = CLAMP((y + r_add) >> SCALEBITS);
337 *g = CLAMP((y + g_add) >> SCALEBITS);
338 *b = CLAMP((y + b_add) >> SCALEBITS);
341 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
342 int r, int g, int b )
344 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
345 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
346 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
349 /***********************************************************************
351 ***********************************************************************/
352 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
353 picture_t *p_dst_orig, picture_t *p_src,
354 int i_x_offset, int i_y_offset,
355 int i_width, int i_height, int i_alpha )
357 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
358 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
359 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
360 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
362 int i_x, i_y, i_trans = 0;
363 bool b_even_scanline = i_y_offset % 2;
365 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
366 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
367 p_filter->fmt_out.video.i_x_offset +
368 p_dst->p[Y_PLANE].i_pitch *
369 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
370 p_dst_u = p_dst->p[U_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[U_PLANE].i_pitch;
374 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
375 p_filter->fmt_out.video.i_x_offset/2 +
376 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
377 p_dst->p[V_PLANE].i_pitch;
379 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
380 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
381 p_filter->fmt_out.video.i_x_offset +
382 p_dst_orig->p[Y_PLANE].i_pitch *
383 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
384 p_src1_u = p_dst_orig->p[U_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[U_PLANE].i_pitch;
388 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
389 p_filter->fmt_out.video.i_x_offset/2 +
390 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
391 p_dst_orig->p[V_PLANE].i_pitch;
393 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
394 p_src2_y = p_src->p[Y_PLANE].p_pixels +
395 p_filter->fmt_in.video.i_x_offset +
396 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
397 p_src2_u = p_src->p[U_PLANE].p_pixels +
398 p_filter->fmt_in.video.i_x_offset/2 +
399 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
400 p_src2_v = p_src->p[V_PLANE].p_pixels +
401 p_filter->fmt_in.video.i_x_offset/2 +
402 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
404 p_trans = p_src->p[A_PLANE].p_pixels +
405 p_filter->fmt_in.video.i_x_offset +
406 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
408 #define MAX_TRANS 255
411 /* Draw until we reach the bottom of the subtitle */
412 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
413 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
414 p_src2_y += i_src2_pitch,
415 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
416 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
417 p_src2_u += i_src2_pitch,
418 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
419 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
420 p_src2_v += i_src2_pitch )
422 b_even_scanline = !b_even_scanline;
424 /* Draw until we reach the end of the line */
425 for( i_x = 0; i_x < i_width; i_x++ )
428 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
431 /* Completely transparent. Don't change pixel */
434 else if( i_trans == MAX_TRANS )
436 /* Completely opaque. Completely overwrite underlying pixel */
437 p_dst_y[i_x] = p_src2_y[i_x];
439 if( b_even_scanline && i_x % 2 == 0 )
441 p_dst_u[i_x/2] = p_src2_u[i_x];
442 p_dst_v[i_x/2] = p_src2_v[i_x];
448 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
449 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
452 if( b_even_scanline && i_x % 2 == 0 )
454 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
455 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
457 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
458 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
470 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
471 picture_t *p_dst_orig, picture_t *p_src,
472 int i_x_offset, int i_y_offset,
473 int i_width, int i_height, int i_alpha )
475 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
476 uint8_t *p_dst, *p_src1, *p_src2_y;
477 uint8_t *p_src2_u, *p_src2_v;
479 int i_x, i_y, i_pix_pitch, i_trans = 0;
482 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
483 i_dst_pitch = p_dst_pic->p->i_pitch;
484 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
485 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
486 p_dst_pic->p->i_pitch *
487 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
489 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
490 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
491 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
492 p_dst_orig->p->i_pitch *
493 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
495 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
496 p_src2_y = p_src->p[Y_PLANE].p_pixels +
497 p_filter->fmt_in.video.i_x_offset +
498 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
499 p_src2_u = p_src->p[U_PLANE].p_pixels +
500 p_filter->fmt_in.video.i_x_offset/2 +
501 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
502 p_src2_v = p_src->p[V_PLANE].p_pixels +
503 p_filter->fmt_in.video.i_x_offset/2 +
504 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
506 p_trans = p_src->p[A_PLANE].p_pixels +
507 p_filter->fmt_in.video.i_x_offset +
508 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
510 #define MAX_TRANS 255
513 /* Draw until we reach the bottom of the subtitle */
514 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
515 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
516 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
517 p_src2_v += i_src2_pitch )
519 /* Draw until we reach the end of the line */
520 for( i_x = 0; i_x < i_width; i_x++ )
523 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
526 /* Completely transparent. Don't change pixel */
529 else if( i_trans == MAX_TRANS )
531 /* Completely opaque. Completely overwrite underlying pixel */
532 yuv_to_rgb( &r, &g, &b,
533 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
535 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
540 /* FIXME: do the blending */
541 yuv_to_rgb( &r, &g, &b,
542 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
544 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
554 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
555 picture_t *p_dst_orig, picture_t *p_src,
556 int i_x_offset, int i_y_offset,
557 int i_width, int i_height, int i_alpha )
559 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
560 uint8_t *p_dst, *p_src1, *p_src2_y;
561 uint8_t *p_src2_u, *p_src2_v;
563 int i_x, i_y, i_pix_pitch, i_trans = 0;
566 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
567 i_dst_pitch = p_dst_pic->p->i_pitch;
568 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
569 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
570 p_dst_pic->p->i_pitch *
571 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
573 i_src1_pitch = p_dst_orig->p->i_pitch;
574 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
575 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
576 p_dst_orig->p->i_pitch *
577 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
579 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
580 p_src2_y = p_src->p[Y_PLANE].p_pixels +
581 p_filter->fmt_in.video.i_x_offset +
582 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
583 p_src2_u = p_src->p[U_PLANE].p_pixels +
584 p_filter->fmt_in.video.i_x_offset/2 +
585 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
586 p_src2_v = p_src->p[V_PLANE].p_pixels +
587 p_filter->fmt_in.video.i_x_offset/2 +
588 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
590 p_trans = p_src->p[A_PLANE].p_pixels +
591 p_filter->fmt_in.video.i_x_offset +
592 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
594 #define MAX_TRANS 255
597 if( (i_pix_pitch == 4)
598 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
602 ** if picture pixels are 32 bits long and lines addresses are 32 bit
603 ** aligned, optimize rendering
605 uint32_t *p32_dst = (uint32_t *)p_dst;
606 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
607 uint32_t *p32_src1 = (uint32_t *)p_src1;
608 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
610 int i_rshift, i_gshift, i_bshift;
611 uint32_t i_rmask, i_gmask, i_bmask;
613 if( p_dst_pic->p_heap )
615 i_rmask = p_dst_pic->p_heap->i_rmask;
616 i_gmask = p_dst_pic->p_heap->i_gmask;
617 i_bmask = p_dst_pic->p_heap->i_bmask;
618 i_rshift = p_dst_pic->p_heap->i_lrshift;
619 i_gshift = p_dst_pic->p_heap->i_lgshift;
620 i_bshift = p_dst_pic->p_heap->i_lbshift;
624 i_rmask = p_dst_pic->format.i_rmask;
625 i_gmask = p_dst_pic->format.i_gmask;
626 i_bmask = p_dst_pic->format.i_bmask;
628 if( (i_rmask == 0x00FF0000)
629 && (i_gmask == 0x0000FF00)
630 && (i_bmask == 0x000000FF) )
632 /* X8R8G8B8 pixel layout */
637 else if( (i_rmask == 0xFF000000)
638 && (i_gmask == 0x00FF0000)
639 && (i_bmask == 0x0000FF00) )
641 /* R8G8B8X8 pixel layout */
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 p32_dst += i32_dst_pitch, p32_src1 += i32_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++ )
661 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
664 /* Completely transparent. Don't change pixel */
667 else if( i_trans == MAX_TRANS )
669 /* Completely opaque. Completely overwrite underlying pixel */
670 yuv_to_rgb( &r, &g, &b,
671 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
673 p32_dst[i_x] = (r<<i_rshift)
680 uint32_t i_pix_src1 = p32_src1[i_x];
681 yuv_to_rgb( &r, &g, &b,
682 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
684 p32_dst[i_x] = ( ( r * i_trans +
685 (uint16_t)((i_pix_src1 & i_rmask)>>i_rshift) *
686 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_rshift
688 (uint16_t)((i_pix_src1 & i_gmask)>>i_gshift) *
689 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_gshift
691 (uint16_t)((i_pix_src1 & i_bmask)>>i_bshift) *
692 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_bshift;
699 int i_rindex, i_bindex, i_gindex;
700 uint32_t i_rmask, i_gmask, i_bmask;
704 i_rmask = p_dst_pic->format.i_rmask;
705 i_gmask = p_dst_pic->format.i_gmask;
706 i_bmask = p_dst_pic->format.i_bmask;
709 ** quick and dirty way to get byte index from mask
710 ** will only work correctly if mask are 8 bit aligned
711 ** and are 8 bit long
713 #ifdef WORDS_BIGENDIAN
714 i_rindex = ((i_rmask>>16) & 1)
717 i_gindex = ((i_gmask>>16) & 1)
720 i_bindex = ((i_bmask>>16) & 1)
724 i_rindex = ((i_rmask>>24) & 3)
725 | ((i_rmask>>16) & 2)
726 | ((i_rmask>>8) & 1);
727 i_gindex = ((i_gmask>>24) & 3)
728 | ((i_gmask>>16) & 2)
729 | ((i_gmask>>8) & 1);
730 i_bindex = ((i_bmask>>24) & 3)
731 | ((i_bmask>>16) & 2)
732 | ((i_bmask>>8) & 1);
735 /* Draw until we reach the bottom of the subtitle */
736 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
737 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
738 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
739 p_src2_v += i_src2_pitch )
741 /* Draw until we reach the end of the line */
742 for( i_x = 0; i_x < i_width; i_x++ )
745 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
748 /* Completely transparent. Don't change pixel */
753 int i_pos = i_x * i_pix_pitch;
754 if( i_trans == MAX_TRANS )
757 /* Completely opaque. Completely overwrite underlying pixel */
758 yuv_to_rgb( &r, &g, &b,
759 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
761 p_dst[i_pos + i_rindex ] = r;
762 p_dst[i_pos + i_gindex ] = g;
763 p_dst[i_pos + i_bindex ] = b;
767 int i_rpos = i_pos + i_rindex;
768 int i_gpos = i_pos + i_gindex;
769 int i_bpos = i_pos + i_bindex;
772 yuv_to_rgb( &r, &g, &b,
773 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
775 p_dst[i_rpos] = ( r * i_trans +
776 (uint16_t)p_src1[i_rpos] *
777 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
778 p_dst[i_gpos] = ( r * i_trans +
779 (uint16_t)p_src1[i_gpos] *
780 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
781 p_dst[i_bpos] = ( r * i_trans +
782 (uint16_t)p_src1[i_gpos] *
783 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
796 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
797 picture_t *p_dst_orig, picture_t *p_src,
798 int i_x_offset, int i_y_offset,
799 int i_width, int i_height, int i_alpha )
801 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
802 uint8_t *p_dst, *p_src1, *p_src2_y;
803 uint8_t *p_src2_u, *p_src2_v;
805 int i_x, i_y, i_pix_pitch, i_trans = 0;
806 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
807 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
809 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
815 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
821 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
829 i_dst_pitch = p_dst_pic->p->i_pitch;
830 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
831 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
832 p_dst_pic->p->i_pitch *
833 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
835 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
836 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
837 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
838 p_dst_orig->p->i_pitch *
839 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
841 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
842 p_src2_y = p_src->p[Y_PLANE].p_pixels +
843 p_filter->fmt_in.video.i_x_offset +
844 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
845 p_src2_u = p_src->p[U_PLANE].p_pixels +
846 p_filter->fmt_in.video.i_x_offset/2 +
847 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
848 p_src2_v = p_src->p[V_PLANE].p_pixels +
849 p_filter->fmt_in.video.i_x_offset/2 +
850 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
852 p_trans = p_src->p[A_PLANE].p_pixels +
853 p_filter->fmt_in.video.i_x_offset +
854 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
856 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
858 #define MAX_TRANS 255
861 /* Draw until we reach the bottom of the subtitle */
862 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
863 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
864 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
865 p_src2_v += i_src2_pitch )
867 /* Draw until we reach the end of the line */
868 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
870 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
873 /* Completely transparent. Don't change pixel */
875 else if( i_trans == MAX_TRANS )
877 /* Completely opaque. Completely overwrite underlying pixel */
878 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
882 if( p_trans[i_x+1] > 0xaa )
884 p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
885 p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
889 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
890 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
897 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_trans +
898 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
905 if( p_trans[i_x+1] > 0xaa )
907 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
908 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
915 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
916 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
918 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
919 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
931 /***********************************************************************
933 ***********************************************************************/
934 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
935 picture_t *p_dst_orig, picture_t *p_src,
936 int i_x_offset, int i_y_offset,
937 int i_width, int i_height, int i_alpha )
939 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
940 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
941 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
942 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
944 bool b_even_scanline = i_y_offset % 2;
946 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
947 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
948 p_filter->fmt_out.video.i_x_offset +
949 p_dst->p[Y_PLANE].i_pitch *
950 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
951 p_dst_u = p_dst->p[U_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[U_PLANE].i_pitch;
955 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
956 p_filter->fmt_out.video.i_x_offset/2 +
957 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
958 p_dst->p[V_PLANE].i_pitch;
960 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
961 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
962 p_filter->fmt_out.video.i_x_offset +
963 p_dst_orig->p[Y_PLANE].i_pitch *
964 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
965 p_src1_u = p_dst_orig->p[U_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[U_PLANE].i_pitch;
969 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
970 p_filter->fmt_out.video.i_x_offset/2 +
971 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
972 p_dst_orig->p[V_PLANE].i_pitch;
974 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
975 p_src2_y = p_src->p[Y_PLANE].p_pixels +
976 p_filter->fmt_in.video.i_x_offset +
977 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
978 p_src2_u = p_src->p[U_PLANE].p_pixels +
979 p_filter->fmt_in.video.i_x_offset/2 +
980 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
981 p_src2_v = p_src->p[V_PLANE].p_pixels +
982 p_filter->fmt_in.video.i_x_offset/2 +
983 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
985 #define MAX_TRANS 255
988 /* Draw until we reach the bottom of the subtitle */
989 for( i_y = 0; i_y < i_height; i_y++,
990 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
991 p_src2_y += i_src2_pitch )
993 if( b_even_scanline )
995 p_dst_u += i_dst_pitch/2;
996 p_dst_v += i_dst_pitch/2;
997 p_src1_u += i_src1_pitch/2;
998 p_src1_v += i_src1_pitch/2;
1000 b_even_scanline = !b_even_scanline;
1002 /* Draw until we reach the end of the line */
1003 for( i_x = 0; i_x < i_width; i_x++ )
1005 if( i_alpha == MAX_TRANS )
1007 /* Completely opaque. Completely overwrite underlying pixel */
1008 p_dst_y[i_x] = p_src2_y[i_x];
1010 if( b_even_scanline && i_x % 2 == 0 )
1012 p_dst_u[i_x/2] = p_src2_u[i_x/2];
1013 p_dst_v[i_x/2] = p_src2_v[i_x/2];
1019 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1020 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_alpha) )
1023 if( b_even_scanline && i_x % 2 == 0 )
1025 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x/2] * i_alpha +
1026 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_alpha) )
1028 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x/2] * i_alpha +
1029 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_alpha) )
1035 p_src2_u += i_src2_pitch/2;
1036 p_src2_v += i_src2_pitch/2;
1045 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
1046 picture_t *p_dst_orig, picture_t *p_src,
1047 int i_x_offset, int i_y_offset,
1048 int i_width, int i_height )
1050 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1051 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
1052 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
1053 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
1055 bool b_even_scanline = i_y_offset % 2;
1057 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1058 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1059 p_filter->fmt_out.video.i_x_offset +
1060 p_dst->p[Y_PLANE].i_pitch *
1061 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1062 p_dst_u = p_dst->p[U_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[U_PLANE].i_pitch;
1066 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1067 p_filter->fmt_out.video.i_x_offset/2 +
1068 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1069 p_dst->p[V_PLANE].i_pitch;
1071 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1072 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1073 p_filter->fmt_out.video.i_x_offset +
1074 p_dst_orig->p[Y_PLANE].i_pitch *
1075 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1076 p_src1_u = p_dst_orig->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_orig->p[U_PLANE].i_pitch;
1080 p_src1_v = p_dst_orig->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_orig->p[V_PLANE].i_pitch;
1085 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1086 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1087 p_filter->fmt_in.video.i_x_offset +
1088 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1089 p_src2_u = p_src->p[U_PLANE].p_pixels +
1090 p_filter->fmt_in.video.i_x_offset/2 +
1091 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1092 p_src2_v = p_src->p[V_PLANE].p_pixels +
1093 p_filter->fmt_in.video.i_x_offset/2 +
1094 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1098 /* Draw until we reach the bottom of the subtitle */
1099 for( i_y = 0; i_y < i_height; i_y++,
1100 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1101 p_src2_y += i_src2_pitch )
1103 /* Completely opaque. Completely overwrite underlying pixel */
1104 vlc_memcpy( p_dst_y, p_src2_y, i_width );
1105 if( b_even_scanline )
1107 p_dst_u += i_dst_pitch/2;
1108 p_dst_v += i_dst_pitch/2;
1109 p_src1_u += i_src1_pitch/2;
1110 p_src1_v += i_src1_pitch/2;
1114 vlc_memcpy( p_dst_u, p_src2_u, i_width/2 );
1115 vlc_memcpy( p_dst_v, p_src2_v, i_width/2 );
1117 b_even_scanline = !b_even_scanline;
1120 p_src2_u += i_src2_pitch/2;
1121 p_src2_v += i_src2_pitch/2;
1128 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1129 picture_t *p_dst_orig, picture_t *p_src,
1130 int i_x_offset, int i_y_offset,
1131 int i_width, int i_height, int i_alpha )
1133 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1134 uint8_t *p_dst, *p_src1, *p_src2_y;
1135 uint8_t *p_src2_u, *p_src2_v;
1136 int i_x, i_y, i_pix_pitch;
1139 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1140 i_dst_pitch = p_dst_pic->p->i_pitch;
1141 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1142 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1143 p_dst_pic->p->i_pitch *
1144 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1146 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1147 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1148 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1149 p_dst_orig->p->i_pitch *
1150 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1152 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1153 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1154 p_filter->fmt_in.video.i_x_offset +
1155 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1156 p_src2_u = p_src->p[U_PLANE].p_pixels +
1157 p_filter->fmt_in.video.i_x_offset/2 +
1158 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1159 p_src2_v = p_src->p[V_PLANE].p_pixels +
1160 p_filter->fmt_in.video.i_x_offset/2 +
1161 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1163 #define MAX_TRANS 255
1164 #define TRANS_BITS 8
1166 /* Draw until we reach the bottom of the subtitle */
1167 for( i_y = 0; i_y < i_height; i_y++,
1168 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1169 p_src2_y += i_src2_pitch )
1171 /* Draw until we reach the end of the line */
1172 for( i_x = 0; i_x < i_width; i_x++ )
1174 if( i_alpha == MAX_TRANS )
1176 /* Completely opaque. Completely overwrite underlying pixel */
1177 yuv_to_rgb( &r, &g, &b,
1178 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1180 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1185 /* FIXME: do the blending */
1186 yuv_to_rgb( &r, &g, &b,
1187 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1189 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1193 p_src2_u += i_src2_pitch/2;
1194 p_src2_v += i_src2_pitch/2;
1204 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1205 picture_t *p_dst_orig, picture_t *p_src,
1206 int i_x_offset, int i_y_offset,
1207 int i_width, int i_height, int i_alpha )
1209 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1210 uint8_t *p_dst, *p_src1, *p_src2_y;
1211 uint8_t *p_src2_u, *p_src2_v;
1212 int i_x, i_y, i_pix_pitch;
1215 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1216 i_dst_pitch = p_dst_pic->p->i_pitch;
1217 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1218 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1219 p_dst_pic->p->i_pitch *
1220 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1222 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1223 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1224 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1225 p_dst_orig->p->i_pitch *
1226 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1228 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1229 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1230 p_filter->fmt_in.video.i_x_offset +
1231 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1232 p_src2_u = p_src->p[U_PLANE].p_pixels +
1233 p_filter->fmt_in.video.i_x_offset/2 +
1234 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1235 p_src2_v = p_src->p[V_PLANE].p_pixels +
1236 p_filter->fmt_in.video.i_x_offset/2 +
1237 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1239 #define MAX_TRANS 255
1240 #define TRANS_BITS 8
1242 /* Draw until we reach the bottom of the subtitle */
1243 for( i_y = 0; i_y < i_height; i_y++,
1244 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1245 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1246 p_src2_v += i_src2_pitch )
1248 /* Draw until we reach the end of the line */
1249 for( i_x = 0; i_x < i_width; i_x++ )
1251 if( i_alpha == MAX_TRANS )
1253 /* Completely opaque. Completely overwrite underlying pixel */
1254 yuv_to_rgb( &r, &g, &b,
1255 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1257 p_dst[i_x * i_pix_pitch] = r;
1258 p_dst[i_x * i_pix_pitch + 1] = g;
1259 p_dst[i_x * i_pix_pitch + 2] = b;
1264 yuv_to_rgb( &r, &g, &b,
1265 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1267 p_dst[i_x * i_pix_pitch] = ( r * i_alpha +
1268 (uint16_t)p_src1[i_x * i_pix_pitch] *
1269 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1270 p_dst[i_x * i_pix_pitch + 1] = ( g * i_alpha +
1271 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1272 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1273 p_dst[i_x * i_pix_pitch + 2] = ( b * i_alpha +
1274 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1275 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1279 p_src2_u += i_src2_pitch/2;
1280 p_src2_v += i_src2_pitch/2;
1290 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1291 picture_t *p_dst_orig, picture_t *p_src,
1292 int i_x_offset, int i_y_offset,
1293 int i_width, int i_height, int i_alpha )
1295 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1296 uint8_t *p_dst, *p_src1, *p_src2_y;
1297 uint8_t *p_src2_u, *p_src2_v;
1298 int i_x, i_y, i_pix_pitch;
1299 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1300 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1302 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1308 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1314 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1322 i_dst_pitch = p_dst_pic->p->i_pitch;
1323 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1324 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1325 p_dst_pic->p->i_pitch *
1326 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1328 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1329 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1330 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1331 p_dst_orig->p->i_pitch *
1332 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1334 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1335 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1336 p_filter->fmt_in.video.i_x_offset +
1337 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1338 p_src2_u = p_src->p[U_PLANE].p_pixels +
1339 p_filter->fmt_in.video.i_x_offset/2 +
1340 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1341 p_src2_v = p_src->p[V_PLANE].p_pixels +
1342 p_filter->fmt_in.video.i_x_offset/2 +
1343 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1345 i_width &= ~1; /* Needs to be a multiple of 2 */
1347 #define MAX_TRANS 255
1348 #define TRANS_BITS 8
1350 /* Draw until we reach the bottom of the subtitle */
1351 for( i_y = 0; i_y < i_height; i_y++,
1352 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1353 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1354 p_src2_v += i_src2_pitch )
1356 /* Draw until we reach the end of the line */
1357 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1359 if( i_alpha == MAX_TRANS )
1361 /* Completely opaque. Completely overwrite underlying pixel */
1362 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
1366 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x/2];
1367 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x/2];
1373 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1374 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_alpha) )
1379 uint16_t i_u = p_src2_u[i_x/2];
1380 uint16_t i_v = p_src2_v[i_x/2];
1381 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_alpha +
1382 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_alpha) )
1384 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_alpha +
1385 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_alpha) )
1392 p_src2_u += i_src2_pitch/2;
1393 p_src2_v += i_src2_pitch/2;
1403 /***********************************************************************
1405 ***********************************************************************/
1406 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1407 picture_t *p_dst_orig, picture_t *p_src,
1408 int i_x_offset, int i_y_offset,
1409 int i_width, int i_height, int i_alpha )
1411 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1412 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1413 uint8_t *p_src1_u, *p_dst_u;
1414 uint8_t *p_src1_v, *p_dst_v;
1415 int i_x, i_y, i_trans;
1416 bool b_even_scanline = i_y_offset % 2;
1418 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1419 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1420 p_filter->fmt_out.video.i_x_offset +
1421 p_dst->p[Y_PLANE].i_pitch *
1422 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1423 p_dst_u = p_dst->p[U_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[U_PLANE].i_pitch;
1427 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1428 p_filter->fmt_out.video.i_x_offset/2 +
1429 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1430 p_dst->p[V_PLANE].i_pitch;
1432 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1433 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1434 p_filter->fmt_out.video.i_x_offset +
1435 p_dst_orig->p[Y_PLANE].i_pitch *
1436 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1437 p_src1_u = p_dst_orig->p[U_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[U_PLANE].i_pitch;
1441 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1442 p_filter->fmt_out.video.i_x_offset/2 +
1443 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1444 p_dst_orig->p[V_PLANE].i_pitch;
1446 i_src2_pitch = p_src->p->i_pitch;
1447 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1448 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1450 #define MAX_TRANS 255
1451 #define TRANS_BITS 8
1452 #define p_trans p_src2
1453 #define p_pal p_filter->fmt_in.video.p_palette->palette
1455 /* Draw until we reach the bottom of the subtitle */
1456 for( i_y = 0; i_y < i_height; i_y++,
1457 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1458 p_src2 += i_src2_pitch,
1459 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1460 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1461 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1462 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1464 b_even_scanline = !b_even_scanline;
1466 /* Draw until we reach the end of the line */
1467 for( i_x = 0; i_x < i_width; i_x++ )
1469 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1472 /* Completely transparent. Don't change pixel */
1475 else if( i_trans == MAX_TRANS )
1477 /* Completely opaque. Completely overwrite underlying pixel */
1478 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
1480 if( b_even_scanline && ((i_x % 2) == 0) )
1482 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
1483 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
1489 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
1490 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1493 if( b_even_scanline && ((i_x % 2) == 0) )
1495 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
1496 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1498 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
1499 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1513 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1514 picture_t *p_dst_orig, picture_t *p_src,
1515 int i_x_offset, int i_y_offset,
1516 int i_width, int i_height, int i_alpha )
1518 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1519 uint8_t *p_src1, *p_src2, *p_dst;
1520 int i_x, i_y, i_pix_pitch, i_trans;
1521 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1522 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1524 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1530 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1536 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1544 i_dst_pitch = p_dst_pic->p->i_pitch;
1545 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1546 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1547 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1549 i_src1_pitch = p_dst_orig->p->i_pitch;
1550 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1551 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1552 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1554 i_src2_pitch = p_src->p->i_pitch;
1555 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1556 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1558 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1560 #define MAX_TRANS 255
1561 #define TRANS_BITS 8
1562 #define p_trans p_src2
1563 #define p_pal p_filter->fmt_in.video.p_palette->palette
1565 /* Draw until we reach the bottom of the subtitle */
1566 for( i_y = 0; i_y < i_height; i_y++,
1567 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1569 /* Draw until we reach the end of the line */
1570 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1572 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1575 /* Completely transparent. Don't change pixel */
1577 else if( i_trans == MAX_TRANS )
1579 /* Completely opaque. Completely overwrite underlying pixel */
1580 p_dst[i_x * 2 + i_l_offset] = p_pal[p_src2[i_x]][0];
1584 if( p_trans[i_x+1] > 0xaa )
1586 p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1587 p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1591 p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1592 p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1599 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1600 i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1601 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1607 if( p_trans[i_x+1] > 0xaa )
1609 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1610 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1614 i_u = p_pal[p_src2[i_x]][1];
1615 i_v = p_pal[p_src2[i_x]][2];
1618 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1619 i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1620 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1621 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1622 i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1623 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1637 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1638 picture_t *p_dst_orig, picture_t *p_src,
1639 int i_x_offset, int i_y_offset,
1640 int i_width, int i_height, int i_alpha )
1642 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1643 uint8_t *p_src1, *p_src2, *p_dst;
1644 int i_x, i_y, i_pix_pitch, i_trans;
1646 video_palette_t rgbpalette;
1648 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1649 i_dst_pitch = p_dst_pic->p->i_pitch;
1650 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1651 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1652 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1654 i_src1_pitch = p_dst_orig->p->i_pitch;
1655 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1656 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1657 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1659 i_src2_pitch = p_src->p->i_pitch;
1660 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1661 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1663 #define MAX_TRANS 255
1664 #define TRANS_BITS 8
1665 #define p_trans p_src2
1666 #define p_pal p_filter->fmt_in.video.p_palette->palette
1667 #define rgbpal rgbpalette.palette
1669 /* Convert palette first */
1670 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1673 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1675 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1677 *(uint16_t *)rgbpal[i_y] =
1678 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1682 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1686 /* Draw until we reach the bottom of the subtitle */
1687 for( i_y = 0; i_y < i_height; i_y++,
1688 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1690 /* Draw until we reach the end of the line */
1691 for( i_x = 0; i_x < i_width; i_x++ )
1693 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1696 /* Completely transparent. Don't change pixel */
1699 else if( i_trans == MAX_TRANS ||
1700 p_filter->fmt_out.video.i_chroma ==
1701 VLC_FOURCC('R','V','1','6') )
1703 /* Completely opaque. Completely overwrite underlying pixel */
1704 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1705 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1706 if( p_filter->fmt_out.video.i_chroma !=
1707 VLC_FOURCC('R','V','1','6') )
1708 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1713 p_dst[i_x * i_pix_pitch] = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1714 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1715 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1716 p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1717 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1718 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1719 p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1720 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1721 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1734 /***********************************************************************
1736 ***********************************************************************/
1737 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1738 picture_t *p_dst_orig, picture_t *p_src,
1739 int i_x_offset, int i_y_offset,
1740 int i_width, int i_height, int i_alpha )
1742 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1743 uint8_t *p_src1_y, *p_dst_y;
1744 uint8_t *p_src1_u, *p_dst_u;
1745 uint8_t *p_src1_v, *p_dst_v;
1747 int i_x, i_y, i_trans;
1750 bool b_even_scanline = i_y_offset % 2;
1752 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1753 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1754 p_filter->fmt_out.video.i_x_offset +
1755 p_dst->p[Y_PLANE].i_pitch *
1756 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1757 p_dst_u = p_dst->p[U_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[U_PLANE].i_pitch;
1761 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1762 p_filter->fmt_out.video.i_x_offset/2 +
1763 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1764 p_dst->p[V_PLANE].i_pitch;
1766 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1767 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1768 p_filter->fmt_out.video.i_x_offset +
1769 p_dst_orig->p[Y_PLANE].i_pitch *
1770 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1771 p_src1_u = p_dst_orig->p[U_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[U_PLANE].i_pitch;
1775 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1776 p_filter->fmt_out.video.i_x_offset/2 +
1777 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1778 p_dst_orig->p[V_PLANE].i_pitch;
1780 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1781 i_src2_pitch = p_src->p->i_pitch;
1782 p_src2 = p_src->p->p_pixels +
1783 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1784 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1787 #define MAX_TRANS 255
1788 #define TRANS_BITS 8
1790 /* Draw until we reach the bottom of the subtitle */
1791 for( i_y = 0; i_y < i_height; i_y++,
1792 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1793 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1794 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1795 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1796 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1797 p_src2 += i_src2_pitch )
1799 b_even_scanline = !b_even_scanline;
1801 /* Draw until we reach the end of the line */
1802 for( i_x = 0; i_x < i_width; i_x++ )
1804 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1805 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1806 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1807 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1810 /* Completely transparent. Don't change pixel */
1813 else if( i_trans == MAX_TRANS )
1815 /* Completely opaque. Completely overwrite underlying pixel */
1816 rgb_to_yuv( &y, &u, &v, R, G, B );
1819 if( b_even_scanline && i_x % 2 == 0 )
1828 rgb_to_yuv( &y, &u, &v, R, G, B );
1829 p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1830 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1833 if( b_even_scanline && i_x % 2 == 0 )
1835 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1836 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1838 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1839 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1854 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1855 picture_t *p_dst_orig, picture_t *p_src,
1856 int i_x_offset, int i_y_offset,
1857 int i_width, int i_height, int i_alpha )
1859 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1860 uint8_t *p_dst, *p_src1, *p_src2;
1861 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1863 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1864 i_dst_pitch = p_dst_pic->p->i_pitch;
1865 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1866 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1867 p_dst_pic->p->i_pitch *
1868 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1870 i_src1_pitch = p_dst_orig->p->i_pitch;
1871 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1872 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1873 p_dst_orig->p->i_pitch *
1874 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1876 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1877 i_src2_pitch = p_src->p->i_pitch;
1878 p_src2 = p_src->p->p_pixels +
1879 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1880 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1882 #define MAX_TRANS 255
1883 #define TRANS_BITS 8
1885 /* Draw until we reach the bottom of the subtitle */
1886 for( i_y = 0; i_y < i_height; i_y++,
1887 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1889 /* Draw until we reach the end of the line */
1890 for( i_x = 0; i_x < i_width; i_x++ )
1892 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1893 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1894 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1895 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1898 /* Completely transparent. Don't change pixel */
1901 else if( i_trans == MAX_TRANS )
1903 /* Completely opaque. Completely overwrite underlying pixel */
1904 p_dst[i_x * i_pix_pitch + 0] = R;
1905 p_dst[i_x * i_pix_pitch + 1] = G;
1906 p_dst[i_x * i_pix_pitch + 2] = B;
1911 p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1912 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1913 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1914 p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1915 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1916 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1917 p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1918 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1919 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1932 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1933 picture_t *p_dst_orig, picture_t *p_src,
1934 int i_x_offset, int i_y_offset,
1935 int i_width, int i_height, int i_alpha )
1937 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1938 uint8_t *p_dst, *p_src1, *p_src2;
1939 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1942 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1943 i_dst_pitch = p_dst_pic->p->i_pitch;
1944 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1945 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1946 p_dst_pic->p->i_pitch *
1947 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1949 i_src1_pitch = p_dst_orig->p->i_pitch;
1950 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1951 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1952 p_dst_orig->p->i_pitch *
1953 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1955 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1956 i_src2_pitch = p_src->p->i_pitch;
1957 p_src2 = p_src->p->p_pixels +
1958 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1959 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1961 #define MAX_TRANS 255
1962 #define TRANS_BITS 8
1964 /* Draw until we reach the bottom of the subtitle */
1965 for( i_y = 0; i_y < i_height; i_y++,
1966 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1968 /* Draw until we reach the end of the line */
1969 for( i_x = 0; i_x < i_width; i_x++ )
1971 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1972 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1973 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1974 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1977 /* Completely transparent. Don't change pixel */
1980 else if( i_trans == MAX_TRANS )
1982 /* Completely opaque. Completely overwrite underlying pixel */
1983 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1988 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1989 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1990 ( ( ( (R >> 3)*i_trans
1991 + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1992 >> TRANS_BITS ) << 11 )
1993 | ( ( ( (G >> 2)*i_trans
1994 + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1995 >> TRANS_BITS ) << 5 )
1996 | ( ( ( (B >> 3)*i_trans
1997 + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
2011 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
2012 picture_t *p_dst_orig, picture_t *p_src,
2013 int i_x_offset, int i_y_offset,
2014 int i_width, int i_height, int i_alpha )
2016 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
2017 uint8_t *p_dst, *p_src1, *p_src2;
2019 int i_x, i_y, i_pix_pitch, i_trans;
2020 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
2021 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
2024 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
2030 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
2036 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
2044 i_dst_pitch = p_dst_pic->p->i_pitch;
2045 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
2046 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2047 p_dst_pic->p->i_pitch *
2048 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2050 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
2051 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
2052 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2053 p_dst_orig->p->i_pitch *
2054 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2056 i_src_pix_pitch = p_src->p->i_pixel_pitch;
2057 i_src2_pitch = p_src->p->i_pitch;
2058 p_src2 = p_src->p->p_pixels +
2059 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
2060 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
2062 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
2064 #define MAX_TRANS 255
2065 #define TRANS_BITS 8
2067 /* Draw until we reach the bottom of the subtitle */
2068 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
2069 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
2070 p_src2 += i_src2_pitch )
2072 /* Draw until we reach the end of the line */
2073 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
2075 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
2076 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
2077 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
2078 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
2081 /* Completely transparent. Don't change pixel */
2083 else if( i_trans == MAX_TRANS )
2085 /* Completely opaque. Completely overwrite underlying pixel */
2086 rgb_to_yuv( &y, &u, &v, R, G, B );
2087 p_dst[i_x * 2 + i_l_offset] = y;
2091 p_dst[i_x * 2 + i_u_offset] = u;
2092 p_dst[i_x * 2 + i_v_offset] = v;
2098 rgb_to_yuv( &y, &u, &v, R, G, B );
2099 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)y * i_trans +
2100 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
2105 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
2106 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
2108 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
2109 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )