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 )
140 p_filter->pf_video_blend = Blend;
142 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
143 (char *)&p_filter->fmt_in.video.i_chroma,
144 (char *)&p_filter->fmt_out.video.i_chroma );
149 /*****************************************************************************
150 * CloseFilter: clean up the filter
151 *****************************************************************************/
152 static void CloseFilter( vlc_object_t *p_this )
154 filter_t *p_filter = (filter_t*)p_this;
155 filter_sys_t *p_sys = p_filter->p_sys;
160 /****************************************************************************
161 * Blend: the whole thing
162 ****************************************************************************
163 * This function is called just after the thread is launched.
164 ****************************************************************************/
165 static void Blend( filter_t *p_filter, picture_t *p_dst,
166 picture_t *p_dst_orig, picture_t *p_src,
167 int i_x_offset, int i_y_offset, int i_alpha )
169 int i_width, i_height;
171 if( i_alpha == 0 ) return;
173 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
174 (int)p_filter->fmt_in.video.i_visible_width);
176 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
177 (int)p_filter->fmt_in.video.i_visible_height);
179 if( i_width <= 0 || i_height <= 0 ) return;
182 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
183 (char *)&p_filter->fmt_in.video.i_chroma,
184 (char *)&p_filter->fmt_out.video.i_chroma );
187 switch( p_filter->fmt_in.video.i_chroma )
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('Y','V','1','2'):
242 case VLC_FOURCC('I','4','2','0'):
243 switch( p_filter->fmt_out.video.i_chroma )
245 case VLC_FOURCC('I','4','2','0'):
246 case VLC_FOURCC('Y','V','1','2'):
247 if( i_alpha == 0xff )
248 BlendI420I420_no_alpha(
249 p_filter, p_dst, p_dst_orig, p_src,
250 i_x_offset, i_y_offset,
253 BlendI420I420( 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('Y','U','Y','2'):
258 case VLC_FOURCC('U','Y','V','Y'):
259 case VLC_FOURCC('Y','V','Y','U'):
260 BlendI420YUVPacked( p_filter, p_dst, p_dst_orig, p_src,
261 i_x_offset, i_y_offset,
262 i_width, i_height, i_alpha );
264 case VLC_FOURCC('R','V','1','6'):
265 BlendI420R16( p_filter, p_dst, p_dst_orig, p_src,
266 i_x_offset, i_y_offset,
267 i_width, i_height, i_alpha );
269 case VLC_FOURCC('R','V','2','4'):
270 case VLC_FOURCC('R','V','3','2'):
271 BlendI420R24( p_filter, p_dst, p_dst_orig, p_src,
272 i_x_offset, i_y_offset,
273 i_width, i_height, i_alpha );
276 case VLC_FOURCC('R','G','B','A'):
277 switch( p_filter->fmt_out.video.i_chroma )
279 case VLC_FOURCC('I','4','2','0'):
280 case VLC_FOURCC('Y','V','1','2'):
281 BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
282 i_x_offset, i_y_offset,
283 i_width, i_height, i_alpha );
285 case VLC_FOURCC('Y','U','Y','2'):
286 case VLC_FOURCC('U','Y','V','Y'):
287 case VLC_FOURCC('Y','V','Y','U'):
288 BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
289 i_x_offset, i_y_offset,
290 i_width, i_height, i_alpha );
292 case VLC_FOURCC('R','V','2','4'):
293 case VLC_FOURCC('R','V','3','2'):
294 BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
295 i_x_offset, i_y_offset,
296 i_width, i_height, i_alpha );
298 case VLC_FOURCC('R','V','1','6'):
299 BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
300 i_x_offset, i_y_offset,
301 i_width, i_height, i_alpha );
306 msg_Dbg( p_filter, "no matching alpha blending routine "
307 "(chroma: %4.4s -> %4.4s)",
308 (char *)&p_filter->fmt_in.video.i_chroma,
309 (char *)&p_filter->fmt_out.video.i_chroma );
312 /***********************************************************************
314 ***********************************************************************/
315 static inline uint8_t vlc_uint8( int v )
324 static inline void yuv_to_rgb( int *r, int *g, int *b,
325 uint8_t y1, uint8_t u1, uint8_t v1 )
327 /* macros used for YUV pixel conversions */
328 # define SCALEBITS 10
329 # define ONE_HALF (1 << (SCALEBITS - 1))
330 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
332 int y, cb, cr, r_add, g_add, b_add;
336 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
337 g_add = - FIX(0.34414*255.0/224.0) * cb
338 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
339 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
340 y = (y1 - 16) * FIX(255.0/219.0);
341 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
342 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
343 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
349 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
350 int r, int g, int b )
352 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
353 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
354 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
357 /***********************************************************************
359 ***********************************************************************/
360 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
361 picture_t *p_dst_orig, picture_t *p_src,
362 int i_x_offset, int i_y_offset,
363 int i_width, int i_height, int i_alpha )
365 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
366 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
367 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
368 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
370 int i_x, i_y, i_trans = 0;
371 bool b_even_scanline = i_y_offset % 2;
373 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
374 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
375 p_filter->fmt_out.video.i_x_offset +
376 p_dst->p[Y_PLANE].i_pitch *
377 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
378 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
379 p_filter->fmt_out.video.i_x_offset/2 +
380 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
381 p_dst->p[U_PLANE].i_pitch;
382 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
383 p_filter->fmt_out.video.i_x_offset/2 +
384 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
385 p_dst->p[V_PLANE].i_pitch;
387 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
388 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
389 p_filter->fmt_out.video.i_x_offset +
390 p_dst_orig->p[Y_PLANE].i_pitch *
391 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
392 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
393 p_filter->fmt_out.video.i_x_offset/2 +
394 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
395 p_dst_orig->p[U_PLANE].i_pitch;
396 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
397 p_filter->fmt_out.video.i_x_offset/2 +
398 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
399 p_dst_orig->p[V_PLANE].i_pitch;
401 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
402 p_src2_y = p_src->p[Y_PLANE].p_pixels +
403 p_filter->fmt_in.video.i_x_offset +
404 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
405 p_src2_u = p_src->p[U_PLANE].p_pixels +
406 p_filter->fmt_in.video.i_x_offset/2 +
407 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
408 p_src2_v = p_src->p[V_PLANE].p_pixels +
409 p_filter->fmt_in.video.i_x_offset/2 +
410 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
412 p_trans = p_src->p[A_PLANE].p_pixels +
413 p_filter->fmt_in.video.i_x_offset +
414 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
416 #define MAX_TRANS 255
419 /* Draw until we reach the bottom of the subtitle */
420 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
421 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
422 p_src2_y += i_src2_pitch,
423 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
424 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
425 p_src2_u += i_src2_pitch,
426 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
427 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
428 p_src2_v += i_src2_pitch )
430 b_even_scanline = !b_even_scanline;
432 /* Draw until we reach the end of the line */
433 for( i_x = 0; i_x < i_width; i_x++ )
436 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
439 /* Completely transparent. Don't change pixel */
442 else if( i_trans == MAX_TRANS )
444 /* Completely opaque. Completely overwrite underlying pixel */
445 p_dst_y[i_x] = p_src2_y[i_x];
447 if( b_even_scanline && i_x % 2 == 0 )
449 p_dst_u[i_x/2] = p_src2_u[i_x];
450 p_dst_v[i_x/2] = p_src2_v[i_x];
456 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
457 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
460 if( b_even_scanline && i_x % 2 == 0 )
462 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
463 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
465 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
466 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
478 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
479 picture_t *p_dst_orig, picture_t *p_src,
480 int i_x_offset, int i_y_offset,
481 int i_width, int i_height, int i_alpha )
483 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
484 uint8_t *p_dst, *p_src1, *p_src2_y;
485 uint8_t *p_src2_u, *p_src2_v;
487 int i_x, i_y, i_pix_pitch, i_trans = 0;
490 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
491 i_dst_pitch = p_dst_pic->p->i_pitch;
492 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
493 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
494 p_dst_pic->p->i_pitch *
495 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
497 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
498 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
499 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
500 p_dst_orig->p->i_pitch *
501 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
503 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
504 p_src2_y = p_src->p[Y_PLANE].p_pixels +
505 p_filter->fmt_in.video.i_x_offset +
506 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
507 p_src2_u = p_src->p[U_PLANE].p_pixels +
508 p_filter->fmt_in.video.i_x_offset/2 +
509 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
510 p_src2_v = p_src->p[V_PLANE].p_pixels +
511 p_filter->fmt_in.video.i_x_offset/2 +
512 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
514 p_trans = p_src->p[A_PLANE].p_pixels +
515 p_filter->fmt_in.video.i_x_offset +
516 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
518 #define MAX_TRANS 255
521 /* Draw until we reach the bottom of the subtitle */
522 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
523 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
524 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
525 p_src2_v += i_src2_pitch )
527 /* Draw until we reach the end of the line */
528 for( i_x = 0; i_x < i_width; i_x++ )
531 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
534 /* Completely transparent. Don't change pixel */
537 else if( i_trans == MAX_TRANS )
539 /* Completely opaque. Completely overwrite underlying pixel */
540 yuv_to_rgb( &r, &g, &b,
541 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
543 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
548 /* FIXME: do the blending */
549 yuv_to_rgb( &r, &g, &b,
550 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
552 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
562 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
563 picture_t *p_dst_orig, picture_t *p_src,
564 int i_x_offset, int i_y_offset,
565 int i_width, int i_height, int i_alpha )
567 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
568 uint8_t *p_dst, *p_src1, *p_src2_y;
569 uint8_t *p_src2_u, *p_src2_v;
571 int i_x, i_y, i_pix_pitch, i_trans = 0;
574 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
575 i_dst_pitch = p_dst_pic->p->i_pitch;
576 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
577 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
578 p_dst_pic->p->i_pitch *
579 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
581 i_src1_pitch = p_dst_orig->p->i_pitch;
582 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
583 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
584 p_dst_orig->p->i_pitch *
585 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
587 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
588 p_src2_y = p_src->p[Y_PLANE].p_pixels +
589 p_filter->fmt_in.video.i_x_offset +
590 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
591 p_src2_u = p_src->p[U_PLANE].p_pixels +
592 p_filter->fmt_in.video.i_x_offset/2 +
593 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
594 p_src2_v = p_src->p[V_PLANE].p_pixels +
595 p_filter->fmt_in.video.i_x_offset/2 +
596 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
598 p_trans = p_src->p[A_PLANE].p_pixels +
599 p_filter->fmt_in.video.i_x_offset +
600 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
602 #define MAX_TRANS 255
605 if( (i_pix_pitch == 4)
606 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
610 ** if picture pixels are 32 bits long and lines addresses are 32 bit
611 ** aligned, optimize rendering
613 uint32_t *p32_dst = (uint32_t *)p_dst;
614 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
615 uint32_t *p32_src1 = (uint32_t *)p_src1;
616 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
618 int i_rshift, i_gshift, i_bshift;
619 uint32_t i_rmask, i_gmask, i_bmask;
621 if( p_dst_pic->p_heap )
623 i_rmask = p_dst_pic->p_heap->i_rmask;
624 i_gmask = p_dst_pic->p_heap->i_gmask;
625 i_bmask = p_dst_pic->p_heap->i_bmask;
626 i_rshift = p_dst_pic->p_heap->i_lrshift;
627 i_gshift = p_dst_pic->p_heap->i_lgshift;
628 i_bshift = p_dst_pic->p_heap->i_lbshift;
632 i_rmask = p_dst_pic->format.i_rmask;
633 i_gmask = p_dst_pic->format.i_gmask;
634 i_bmask = p_dst_pic->format.i_bmask;
636 if( (i_rmask == 0x00FF0000)
637 && (i_gmask == 0x0000FF00)
638 && (i_bmask == 0x000000FF) )
640 /* X8R8G8B8 pixel layout */
645 else if( (i_rmask == 0xFF000000)
646 && (i_gmask == 0x00FF0000)
647 && (i_bmask == 0x0000FF00) )
649 /* R8G8B8X8 pixel layout */
659 /* Draw until we reach the bottom of the subtitle */
660 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
661 p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
662 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
663 p_src2_v += i_src2_pitch )
665 /* Draw until we reach the end of the line */
666 for( i_x = 0; i_x < i_width; i_x++ )
669 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
672 /* Completely transparent. Don't change pixel */
675 else if( i_trans == MAX_TRANS )
677 /* Completely opaque. Completely overwrite underlying pixel */
678 yuv_to_rgb( &r, &g, &b,
679 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
681 p32_dst[i_x] = (r<<i_rshift)
688 uint32_t i_pix_src1 = p32_src1[i_x];
689 yuv_to_rgb( &r, &g, &b,
690 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
692 p32_dst[i_x] = ( ( r * i_trans +
693 (uint16_t)((i_pix_src1 & i_rmask)>>i_rshift) *
694 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_rshift
696 (uint16_t)((i_pix_src1 & i_gmask)>>i_gshift) *
697 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_gshift
699 (uint16_t)((i_pix_src1 & i_bmask)>>i_bshift) *
700 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_bshift;
707 int i_rindex, i_bindex, i_gindex;
708 uint32_t i_rmask, i_gmask, i_bmask;
712 i_rmask = p_dst_pic->format.i_rmask;
713 i_gmask = p_dst_pic->format.i_gmask;
714 i_bmask = p_dst_pic->format.i_bmask;
717 ** quick and dirty way to get byte index from mask
718 ** will only work correctly if mask are 8 bit aligned
719 ** and are 8 bit long
721 #ifdef WORDS_BIGENDIAN
722 i_rindex = ((i_rmask>>16) & 1)
725 i_gindex = ((i_gmask>>16) & 1)
728 i_bindex = ((i_bmask>>16) & 1)
732 i_rindex = ((i_rmask>>24) & 3)
733 | ((i_rmask>>16) & 2)
734 | ((i_rmask>>8) & 1);
735 i_gindex = ((i_gmask>>24) & 3)
736 | ((i_gmask>>16) & 2)
737 | ((i_gmask>>8) & 1);
738 i_bindex = ((i_bmask>>24) & 3)
739 | ((i_bmask>>16) & 2)
740 | ((i_bmask>>8) & 1);
743 /* Draw until we reach the bottom of the subtitle */
744 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
745 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
746 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
747 p_src2_v += i_src2_pitch )
749 /* Draw until we reach the end of the line */
750 for( i_x = 0; i_x < i_width; i_x++ )
753 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
756 /* Completely transparent. Don't change pixel */
761 int i_pos = i_x * i_pix_pitch;
762 if( i_trans == MAX_TRANS )
765 /* Completely opaque. Completely overwrite underlying pixel */
766 yuv_to_rgb( &r, &g, &b,
767 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
769 p_dst[i_pos + i_rindex ] = r;
770 p_dst[i_pos + i_gindex ] = g;
771 p_dst[i_pos + i_bindex ] = b;
775 int i_rpos = i_pos + i_rindex;
776 int i_gpos = i_pos + i_gindex;
777 int i_bpos = i_pos + i_bindex;
780 yuv_to_rgb( &r, &g, &b,
781 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
783 p_dst[i_rpos] = ( r * i_trans +
784 (uint16_t)p_src1[i_rpos] *
785 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
786 p_dst[i_gpos] = ( r * i_trans +
787 (uint16_t)p_src1[i_gpos] *
788 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
789 p_dst[i_bpos] = ( r * i_trans +
790 (uint16_t)p_src1[i_gpos] *
791 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
804 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
805 picture_t *p_dst_orig, picture_t *p_src,
806 int i_x_offset, int i_y_offset,
807 int i_width, int i_height, int i_alpha )
809 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
810 uint8_t *p_dst, *p_src1, *p_src2_y;
811 uint8_t *p_src2_u, *p_src2_v;
813 int i_x, i_y, i_pix_pitch, i_trans = 0;
814 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
815 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
817 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
823 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
829 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
837 i_dst_pitch = p_dst_pic->p->i_pitch;
838 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
839 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
840 p_dst_pic->p->i_pitch *
841 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
843 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
844 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
845 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
846 p_dst_orig->p->i_pitch *
847 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
849 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
850 p_src2_y = p_src->p[Y_PLANE].p_pixels +
851 p_filter->fmt_in.video.i_x_offset +
852 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
853 p_src2_u = p_src->p[U_PLANE].p_pixels +
854 p_filter->fmt_in.video.i_x_offset/2 +
855 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
856 p_src2_v = p_src->p[V_PLANE].p_pixels +
857 p_filter->fmt_in.video.i_x_offset/2 +
858 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
860 p_trans = p_src->p[A_PLANE].p_pixels +
861 p_filter->fmt_in.video.i_x_offset +
862 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
864 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
866 #define MAX_TRANS 255
869 /* Draw until we reach the bottom of the subtitle */
870 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
871 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
872 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
873 p_src2_v += i_src2_pitch )
875 /* Draw until we reach the end of the line */
876 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
878 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
881 /* Completely transparent. Don't change pixel */
883 else if( i_trans == MAX_TRANS )
885 /* Completely opaque. Completely overwrite underlying pixel */
886 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
890 if( p_trans[i_x+1] > 0xaa )
892 p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
893 p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
897 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
898 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
905 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_trans +
906 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
913 if( p_trans[i_x+1] > 0xaa )
915 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
916 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
923 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
924 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
926 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
927 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
939 /***********************************************************************
941 ***********************************************************************/
942 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
943 picture_t *p_dst_orig, picture_t *p_src,
944 int i_x_offset, int i_y_offset,
945 int i_width, int i_height, int i_alpha )
947 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
948 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
949 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
950 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
952 bool b_even_scanline = i_y_offset % 2;
954 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
955 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
956 p_filter->fmt_out.video.i_x_offset +
957 p_dst->p[Y_PLANE].i_pitch *
958 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
959 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
960 p_filter->fmt_out.video.i_x_offset/2 +
961 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
962 p_dst->p[U_PLANE].i_pitch;
963 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
964 p_filter->fmt_out.video.i_x_offset/2 +
965 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
966 p_dst->p[V_PLANE].i_pitch;
968 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
969 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
970 p_filter->fmt_out.video.i_x_offset +
971 p_dst_orig->p[Y_PLANE].i_pitch *
972 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
973 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
974 p_filter->fmt_out.video.i_x_offset/2 +
975 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
976 p_dst_orig->p[U_PLANE].i_pitch;
977 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
978 p_filter->fmt_out.video.i_x_offset/2 +
979 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
980 p_dst_orig->p[V_PLANE].i_pitch;
982 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
983 p_src2_y = p_src->p[Y_PLANE].p_pixels +
984 p_filter->fmt_in.video.i_x_offset +
985 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
986 p_src2_u = p_src->p[U_PLANE].p_pixels +
987 p_filter->fmt_in.video.i_x_offset/2 +
988 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
989 p_src2_v = p_src->p[V_PLANE].p_pixels +
990 p_filter->fmt_in.video.i_x_offset/2 +
991 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
993 #define MAX_TRANS 255
996 /* Draw until we reach the bottom of the subtitle */
997 for( i_y = 0; i_y < i_height; i_y++,
998 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
999 p_src2_y += i_src2_pitch )
1001 if( b_even_scanline )
1003 p_dst_u += i_dst_pitch/2;
1004 p_dst_v += i_dst_pitch/2;
1005 p_src1_u += i_src1_pitch/2;
1006 p_src1_v += i_src1_pitch/2;
1008 b_even_scanline = !b_even_scanline;
1010 /* Draw until we reach the end of the line */
1011 for( i_x = 0; i_x < i_width; i_x++ )
1013 if( i_alpha == MAX_TRANS )
1015 /* Completely opaque. Completely overwrite underlying pixel */
1016 p_dst_y[i_x] = p_src2_y[i_x];
1018 if( b_even_scanline && i_x % 2 == 0 )
1020 p_dst_u[i_x/2] = p_src2_u[i_x/2];
1021 p_dst_v[i_x/2] = p_src2_v[i_x/2];
1027 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1028 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_alpha) )
1031 if( b_even_scanline && i_x % 2 == 0 )
1033 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x/2] * i_alpha +
1034 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_alpha) )
1036 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x/2] * i_alpha +
1037 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_alpha) )
1043 p_src2_u += i_src2_pitch/2;
1044 p_src2_v += i_src2_pitch/2;
1053 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
1054 picture_t *p_dst_orig, picture_t *p_src,
1055 int i_x_offset, int i_y_offset,
1056 int i_width, int i_height )
1058 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1059 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
1060 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
1061 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
1063 bool b_even_scanline = i_y_offset % 2;
1065 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1066 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1067 p_filter->fmt_out.video.i_x_offset +
1068 p_dst->p[Y_PLANE].i_pitch *
1069 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1070 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1071 p_filter->fmt_out.video.i_x_offset/2 +
1072 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1073 p_dst->p[U_PLANE].i_pitch;
1074 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1075 p_filter->fmt_out.video.i_x_offset/2 +
1076 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1077 p_dst->p[V_PLANE].i_pitch;
1079 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1080 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1081 p_filter->fmt_out.video.i_x_offset +
1082 p_dst_orig->p[Y_PLANE].i_pitch *
1083 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1084 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1085 p_filter->fmt_out.video.i_x_offset/2 +
1086 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1087 p_dst_orig->p[U_PLANE].i_pitch;
1088 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1089 p_filter->fmt_out.video.i_x_offset/2 +
1090 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1091 p_dst_orig->p[V_PLANE].i_pitch;
1093 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1094 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1095 p_filter->fmt_in.video.i_x_offset +
1096 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1097 p_src2_u = p_src->p[U_PLANE].p_pixels +
1098 p_filter->fmt_in.video.i_x_offset/2 +
1099 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1100 p_src2_v = p_src->p[V_PLANE].p_pixels +
1101 p_filter->fmt_in.video.i_x_offset/2 +
1102 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1106 /* Draw until we reach the bottom of the subtitle */
1107 for( i_y = 0; i_y < i_height; i_y++,
1108 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1109 p_src2_y += i_src2_pitch )
1111 /* Completely opaque. Completely overwrite underlying pixel */
1112 vlc_memcpy( p_dst_y, p_src2_y, i_width );
1113 if( b_even_scanline )
1115 p_dst_u += i_dst_pitch/2;
1116 p_dst_v += i_dst_pitch/2;
1117 p_src1_u += i_src1_pitch/2;
1118 p_src1_v += i_src1_pitch/2;
1122 vlc_memcpy( p_dst_u, p_src2_u, i_width/2 );
1123 vlc_memcpy( p_dst_v, p_src2_v, i_width/2 );
1125 b_even_scanline = !b_even_scanline;
1128 p_src2_u += i_src2_pitch/2;
1129 p_src2_v += i_src2_pitch/2;
1136 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1137 picture_t *p_dst_orig, picture_t *p_src,
1138 int i_x_offset, int i_y_offset,
1139 int i_width, int i_height, int i_alpha )
1141 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1142 uint8_t *p_dst, *p_src1, *p_src2_y;
1143 uint8_t *p_src2_u, *p_src2_v;
1144 int i_x, i_y, i_pix_pitch;
1147 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1148 i_dst_pitch = p_dst_pic->p->i_pitch;
1149 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1150 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1151 p_dst_pic->p->i_pitch *
1152 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1154 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1155 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1156 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1157 p_dst_orig->p->i_pitch *
1158 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1160 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1161 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1162 p_filter->fmt_in.video.i_x_offset +
1163 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1164 p_src2_u = p_src->p[U_PLANE].p_pixels +
1165 p_filter->fmt_in.video.i_x_offset/2 +
1166 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1167 p_src2_v = p_src->p[V_PLANE].p_pixels +
1168 p_filter->fmt_in.video.i_x_offset/2 +
1169 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1171 #define MAX_TRANS 255
1172 #define TRANS_BITS 8
1174 /* Draw until we reach the bottom of the subtitle */
1175 for( i_y = 0; i_y < i_height; i_y++,
1176 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1177 p_src2_y += i_src2_pitch )
1179 /* Draw until we reach the end of the line */
1180 for( i_x = 0; i_x < i_width; i_x++ )
1182 if( i_alpha == MAX_TRANS )
1184 /* Completely opaque. Completely overwrite underlying pixel */
1185 yuv_to_rgb( &r, &g, &b,
1186 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1188 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1193 /* FIXME: do the blending */
1194 yuv_to_rgb( &r, &g, &b,
1195 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1197 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1201 p_src2_u += i_src2_pitch/2;
1202 p_src2_v += i_src2_pitch/2;
1212 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1213 picture_t *p_dst_orig, picture_t *p_src,
1214 int i_x_offset, int i_y_offset,
1215 int i_width, int i_height, int i_alpha )
1217 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1218 uint8_t *p_dst, *p_src1, *p_src2_y;
1219 uint8_t *p_src2_u, *p_src2_v;
1220 int i_x, i_y, i_pix_pitch;
1223 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1224 i_dst_pitch = p_dst_pic->p->i_pitch;
1225 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1226 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1227 p_dst_pic->p->i_pitch *
1228 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1230 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1231 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1232 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1233 p_dst_orig->p->i_pitch *
1234 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1236 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1237 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1238 p_filter->fmt_in.video.i_x_offset +
1239 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1240 p_src2_u = p_src->p[U_PLANE].p_pixels +
1241 p_filter->fmt_in.video.i_x_offset/2 +
1242 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1243 p_src2_v = p_src->p[V_PLANE].p_pixels +
1244 p_filter->fmt_in.video.i_x_offset/2 +
1245 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1247 #define MAX_TRANS 255
1248 #define TRANS_BITS 8
1250 /* Draw until we reach the bottom of the subtitle */
1251 for( i_y = 0; i_y < i_height; i_y++,
1252 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1253 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1254 p_src2_v += i_src2_pitch )
1256 /* Draw until we reach the end of the line */
1257 for( i_x = 0; i_x < i_width; i_x++ )
1259 if( i_alpha == MAX_TRANS )
1261 /* Completely opaque. Completely overwrite underlying pixel */
1262 yuv_to_rgb( &r, &g, &b,
1263 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1265 p_dst[i_x * i_pix_pitch] = r;
1266 p_dst[i_x * i_pix_pitch + 1] = g;
1267 p_dst[i_x * i_pix_pitch + 2] = b;
1272 yuv_to_rgb( &r, &g, &b,
1273 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1275 p_dst[i_x * i_pix_pitch] = ( r * i_alpha +
1276 (uint16_t)p_src1[i_x * i_pix_pitch] *
1277 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1278 p_dst[i_x * i_pix_pitch + 1] = ( g * i_alpha +
1279 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1280 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1281 p_dst[i_x * i_pix_pitch + 2] = ( b * i_alpha +
1282 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1283 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1287 p_src2_u += i_src2_pitch/2;
1288 p_src2_v += i_src2_pitch/2;
1298 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1299 picture_t *p_dst_orig, picture_t *p_src,
1300 int i_x_offset, int i_y_offset,
1301 int i_width, int i_height, int i_alpha )
1303 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1304 uint8_t *p_dst, *p_src1, *p_src2_y;
1305 uint8_t *p_src2_u, *p_src2_v;
1306 int i_x, i_y, i_pix_pitch;
1307 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1308 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1310 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1316 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1322 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1330 i_dst_pitch = p_dst_pic->p->i_pitch;
1331 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1332 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1333 p_dst_pic->p->i_pitch *
1334 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1336 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1337 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1338 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1339 p_dst_orig->p->i_pitch *
1340 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1342 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1343 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1344 p_filter->fmt_in.video.i_x_offset +
1345 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1346 p_src2_u = p_src->p[U_PLANE].p_pixels +
1347 p_filter->fmt_in.video.i_x_offset/2 +
1348 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1349 p_src2_v = p_src->p[V_PLANE].p_pixels +
1350 p_filter->fmt_in.video.i_x_offset/2 +
1351 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1353 i_width &= ~1; /* Needs to be a multiple of 2 */
1355 #define MAX_TRANS 255
1356 #define TRANS_BITS 8
1358 /* Draw until we reach the bottom of the subtitle */
1359 for( i_y = 0; i_y < i_height; i_y++,
1360 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1361 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1362 p_src2_v += i_src2_pitch )
1364 /* Draw until we reach the end of the line */
1365 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1367 if( i_alpha == MAX_TRANS )
1369 /* Completely opaque. Completely overwrite underlying pixel */
1370 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
1374 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x/2];
1375 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x/2];
1381 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1382 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_alpha) )
1387 uint16_t i_u = p_src2_u[i_x/2];
1388 uint16_t i_v = p_src2_v[i_x/2];
1389 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_alpha +
1390 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_alpha) )
1392 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_alpha +
1393 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_alpha) )
1400 p_src2_u += i_src2_pitch/2;
1401 p_src2_v += i_src2_pitch/2;
1411 /***********************************************************************
1413 ***********************************************************************/
1414 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1415 picture_t *p_dst_orig, picture_t *p_src,
1416 int i_x_offset, int i_y_offset,
1417 int i_width, int i_height, int i_alpha )
1419 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1420 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1421 uint8_t *p_src1_u, *p_dst_u;
1422 uint8_t *p_src1_v, *p_dst_v;
1423 int i_x, i_y, i_trans;
1424 bool b_even_scanline = i_y_offset % 2;
1426 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1427 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1428 p_filter->fmt_out.video.i_x_offset +
1429 p_dst->p[Y_PLANE].i_pitch *
1430 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1431 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1432 p_filter->fmt_out.video.i_x_offset/2 +
1433 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1434 p_dst->p[U_PLANE].i_pitch;
1435 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1436 p_filter->fmt_out.video.i_x_offset/2 +
1437 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1438 p_dst->p[V_PLANE].i_pitch;
1440 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1441 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1442 p_filter->fmt_out.video.i_x_offset +
1443 p_dst_orig->p[Y_PLANE].i_pitch *
1444 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1445 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1446 p_filter->fmt_out.video.i_x_offset/2 +
1447 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1448 p_dst_orig->p[U_PLANE].i_pitch;
1449 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1450 p_filter->fmt_out.video.i_x_offset/2 +
1451 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1452 p_dst_orig->p[V_PLANE].i_pitch;
1454 i_src2_pitch = p_src->p->i_pitch;
1455 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1456 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1458 #define MAX_TRANS 255
1459 #define TRANS_BITS 8
1460 #define p_trans p_src2
1461 #define p_pal p_filter->fmt_in.video.p_palette->palette
1463 /* Draw until we reach the bottom of the subtitle */
1464 for( i_y = 0; i_y < i_height; i_y++,
1465 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1466 p_src2 += i_src2_pitch,
1467 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1468 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1469 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1470 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1472 b_even_scanline = !b_even_scanline;
1474 /* Draw until we reach the end of the line */
1475 for( i_x = 0; i_x < i_width; i_x++ )
1477 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1480 /* Completely transparent. Don't change pixel */
1483 else if( i_trans == MAX_TRANS )
1485 /* Completely opaque. Completely overwrite underlying pixel */
1486 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
1488 if( b_even_scanline && ((i_x % 2) == 0) )
1490 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
1491 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
1497 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
1498 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1501 if( b_even_scanline && ((i_x % 2) == 0) )
1503 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
1504 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1506 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
1507 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1521 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1522 picture_t *p_dst_orig, picture_t *p_src,
1523 int i_x_offset, int i_y_offset,
1524 int i_width, int i_height, int i_alpha )
1526 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1527 uint8_t *p_src1, *p_src2, *p_dst;
1528 int i_x, i_y, i_pix_pitch, i_trans;
1529 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1530 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1532 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1538 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1544 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1552 i_dst_pitch = p_dst_pic->p->i_pitch;
1553 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1554 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1555 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1557 i_src1_pitch = p_dst_orig->p->i_pitch;
1558 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1559 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1560 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1562 i_src2_pitch = p_src->p->i_pitch;
1563 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1564 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1566 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1568 #define MAX_TRANS 255
1569 #define TRANS_BITS 8
1570 #define p_trans p_src2
1571 #define p_pal p_filter->fmt_in.video.p_palette->palette
1573 /* Draw until we reach the bottom of the subtitle */
1574 for( i_y = 0; i_y < i_height; i_y++,
1575 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1577 /* Draw until we reach the end of the line */
1578 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1580 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1583 /* Completely transparent. Don't change pixel */
1585 else if( i_trans == MAX_TRANS )
1587 /* Completely opaque. Completely overwrite underlying pixel */
1588 p_dst[i_x * 2 + i_l_offset] = p_pal[p_src2[i_x]][0];
1592 if( p_trans[i_x+1] > 0xaa )
1594 p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1595 p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1599 p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1600 p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1607 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1608 i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1609 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1615 if( p_trans[i_x+1] > 0xaa )
1617 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1618 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1622 i_u = p_pal[p_src2[i_x]][1];
1623 i_v = p_pal[p_src2[i_x]][2];
1626 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1627 i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1628 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1629 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1630 i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1631 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1645 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1646 picture_t *p_dst_orig, picture_t *p_src,
1647 int i_x_offset, int i_y_offset,
1648 int i_width, int i_height, int i_alpha )
1650 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1651 uint8_t *p_src1, *p_src2, *p_dst;
1652 int i_x, i_y, i_pix_pitch, i_trans;
1654 video_palette_t rgbpalette;
1656 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1657 i_dst_pitch = p_dst_pic->p->i_pitch;
1658 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1659 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1660 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1662 i_src1_pitch = p_dst_orig->p->i_pitch;
1663 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1664 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1665 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1667 i_src2_pitch = p_src->p->i_pitch;
1668 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1669 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1671 #define MAX_TRANS 255
1672 #define TRANS_BITS 8
1673 #define p_trans p_src2
1674 #define p_pal p_filter->fmt_in.video.p_palette->palette
1675 #define rgbpal rgbpalette.palette
1677 /* Convert palette first */
1678 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1681 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1683 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1685 *(uint16_t *)rgbpal[i_y] =
1686 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1690 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1694 /* Draw until we reach the bottom of the subtitle */
1695 for( i_y = 0; i_y < i_height; i_y++,
1696 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1698 /* Draw until we reach the end of the line */
1699 for( i_x = 0; i_x < i_width; i_x++ )
1701 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1704 /* Completely transparent. Don't change pixel */
1707 else if( i_trans == MAX_TRANS ||
1708 p_filter->fmt_out.video.i_chroma ==
1709 VLC_FOURCC('R','V','1','6') )
1711 /* Completely opaque. Completely overwrite underlying pixel */
1712 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1713 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1714 if( p_filter->fmt_out.video.i_chroma !=
1715 VLC_FOURCC('R','V','1','6') )
1716 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1721 p_dst[i_x * i_pix_pitch] = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1722 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1723 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1724 p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1725 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1726 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1727 p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1728 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1729 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1742 /***********************************************************************
1744 ***********************************************************************/
1745 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1746 picture_t *p_dst_orig, picture_t *p_src,
1747 int i_x_offset, int i_y_offset,
1748 int i_width, int i_height, int i_alpha )
1750 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1751 uint8_t *p_src1_y, *p_dst_y;
1752 uint8_t *p_src1_u, *p_dst_u;
1753 uint8_t *p_src1_v, *p_dst_v;
1755 int i_x, i_y, i_trans;
1758 bool b_even_scanline = i_y_offset % 2;
1760 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1761 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1762 p_filter->fmt_out.video.i_x_offset +
1763 p_dst->p[Y_PLANE].i_pitch *
1764 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1765 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1766 p_filter->fmt_out.video.i_x_offset/2 +
1767 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1768 p_dst->p[U_PLANE].i_pitch;
1769 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1770 p_filter->fmt_out.video.i_x_offset/2 +
1771 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1772 p_dst->p[V_PLANE].i_pitch;
1774 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1775 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1776 p_filter->fmt_out.video.i_x_offset +
1777 p_dst_orig->p[Y_PLANE].i_pitch *
1778 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1779 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1780 p_filter->fmt_out.video.i_x_offset/2 +
1781 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1782 p_dst_orig->p[U_PLANE].i_pitch;
1783 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1784 p_filter->fmt_out.video.i_x_offset/2 +
1785 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1786 p_dst_orig->p[V_PLANE].i_pitch;
1788 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1789 i_src2_pitch = p_src->p->i_pitch;
1790 p_src2 = p_src->p->p_pixels +
1791 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1792 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1795 #define MAX_TRANS 255
1796 #define TRANS_BITS 8
1798 /* Draw until we reach the bottom of the subtitle */
1799 for( i_y = 0; i_y < i_height; i_y++,
1800 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1801 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1802 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1803 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1804 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1805 p_src2 += i_src2_pitch )
1807 b_even_scanline = !b_even_scanline;
1809 /* Draw until we reach the end of the line */
1810 for( i_x = 0; i_x < i_width; i_x++ )
1812 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1813 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1814 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1815 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1818 /* Completely transparent. Don't change pixel */
1821 else if( i_trans == MAX_TRANS )
1823 /* Completely opaque. Completely overwrite underlying pixel */
1824 rgb_to_yuv( &y, &u, &v, R, G, B );
1827 if( b_even_scanline && i_x % 2 == 0 )
1836 rgb_to_yuv( &y, &u, &v, R, G, B );
1837 p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1838 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1841 if( b_even_scanline && i_x % 2 == 0 )
1843 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1844 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1846 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1847 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1862 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1863 picture_t *p_dst_orig, picture_t *p_src,
1864 int i_x_offset, int i_y_offset,
1865 int i_width, int i_height, int i_alpha )
1867 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1868 uint8_t *p_dst, *p_src1, *p_src2;
1869 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1871 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1872 i_dst_pitch = p_dst_pic->p->i_pitch;
1873 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1874 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1875 p_dst_pic->p->i_pitch *
1876 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1878 i_src1_pitch = p_dst_orig->p->i_pitch;
1879 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1880 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1881 p_dst_orig->p->i_pitch *
1882 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1884 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1885 i_src2_pitch = p_src->p->i_pitch;
1886 p_src2 = p_src->p->p_pixels +
1887 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1888 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1890 #define MAX_TRANS 255
1891 #define TRANS_BITS 8
1893 /* Draw until we reach the bottom of the subtitle */
1894 for( i_y = 0; i_y < i_height; i_y++,
1895 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1897 /* Draw until we reach the end of the line */
1898 for( i_x = 0; i_x < i_width; i_x++ )
1900 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1901 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1902 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1903 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1906 /* Completely transparent. Don't change pixel */
1909 else if( i_trans == MAX_TRANS )
1911 /* Completely opaque. Completely overwrite underlying pixel */
1912 p_dst[i_x * i_pix_pitch + 0] = R;
1913 p_dst[i_x * i_pix_pitch + 1] = G;
1914 p_dst[i_x * i_pix_pitch + 2] = B;
1919 p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1920 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1921 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1922 p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1923 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1924 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1925 p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1926 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1927 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1940 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1941 picture_t *p_dst_orig, picture_t *p_src,
1942 int i_x_offset, int i_y_offset,
1943 int i_width, int i_height, int i_alpha )
1945 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1946 uint8_t *p_dst, *p_src1, *p_src2;
1947 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1950 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1951 i_dst_pitch = p_dst_pic->p->i_pitch;
1952 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1953 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1954 p_dst_pic->p->i_pitch *
1955 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1957 i_src1_pitch = p_dst_orig->p->i_pitch;
1958 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1959 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1960 p_dst_orig->p->i_pitch *
1961 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1963 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1964 i_src2_pitch = p_src->p->i_pitch;
1965 p_src2 = p_src->p->p_pixels +
1966 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1967 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1969 #define MAX_TRANS 255
1970 #define TRANS_BITS 8
1972 /* Draw until we reach the bottom of the subtitle */
1973 for( i_y = 0; i_y < i_height; i_y++,
1974 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1976 /* Draw until we reach the end of the line */
1977 for( i_x = 0; i_x < i_width; i_x++ )
1979 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1980 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1981 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1982 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1985 /* Completely transparent. Don't change pixel */
1988 else if( i_trans == MAX_TRANS )
1990 /* Completely opaque. Completely overwrite underlying pixel */
1991 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1996 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1997 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1998 ( ( ( (R >> 3)*i_trans
1999 + (i_pix >> 11) * (MAX_TRANS - i_trans) )
2000 >> TRANS_BITS ) << 11 )
2001 | ( ( ( (G >> 2)*i_trans
2002 + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
2003 >> TRANS_BITS ) << 5 )
2004 | ( ( ( (B >> 3)*i_trans
2005 + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
2019 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
2020 picture_t *p_dst_orig, picture_t *p_src,
2021 int i_x_offset, int i_y_offset,
2022 int i_width, int i_height, int i_alpha )
2024 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
2025 uint8_t *p_dst, *p_src1, *p_src2;
2027 int i_x, i_y, i_pix_pitch, i_trans;
2028 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
2029 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
2032 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
2038 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
2044 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
2052 i_dst_pitch = p_dst_pic->p->i_pitch;
2053 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
2054 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2055 p_dst_pic->p->i_pitch *
2056 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2058 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
2059 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
2060 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2061 p_dst_orig->p->i_pitch *
2062 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2064 i_src_pix_pitch = p_src->p->i_pixel_pitch;
2065 i_src2_pitch = p_src->p->i_pitch;
2066 p_src2 = p_src->p->p_pixels +
2067 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
2068 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
2070 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
2072 #define MAX_TRANS 255
2073 #define TRANS_BITS 8
2075 /* Draw until we reach the bottom of the subtitle */
2076 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
2077 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
2078 p_src2 += i_src2_pitch )
2080 /* Draw until we reach the end of the line */
2081 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
2083 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
2084 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
2085 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
2086 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
2089 /* Completely transparent. Don't change pixel */
2091 else if( i_trans == MAX_TRANS )
2093 /* Completely opaque. Completely overwrite underlying pixel */
2094 rgb_to_yuv( &y, &u, &v, R, G, B );
2095 p_dst[i_x * 2 + i_l_offset] = y;
2099 p_dst[i_x * 2 + i_u_offset] = u;
2100 p_dst[i_x * 2 + i_v_offset] = v;
2106 rgb_to_yuv( &y, &u, &v, R, G, B );
2107 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)y * i_trans +
2108 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
2113 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
2114 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
2116 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
2117 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )