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 void yuv_to_rgb( int *r, int *g, int *b,
316 uint8_t y1, uint8_t u1, uint8_t v1 )
318 /* macros used for YUV pixel conversions */
319 # define SCALEBITS 10
320 # define ONE_HALF (1 << (SCALEBITS - 1))
321 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
322 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
324 int y, cb, cr, r_add, g_add, b_add;
328 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
329 g_add = - FIX(0.34414*255.0/224.0) * cb
330 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
331 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
332 y = (y1 - 16) * FIX(255.0/219.0);
333 *r = CLAMP((y + r_add) >> SCALEBITS);
334 *g = CLAMP((y + g_add) >> SCALEBITS);
335 *b = CLAMP((y + b_add) >> SCALEBITS);
338 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
339 int r, int g, int b )
341 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
342 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
343 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
346 /***********************************************************************
348 ***********************************************************************/
349 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
350 picture_t *p_dst_orig, picture_t *p_src,
351 int i_x_offset, int i_y_offset,
352 int i_width, int i_height, int i_alpha )
354 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
355 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
356 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
357 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
359 int i_x, i_y, i_trans = 0;
360 bool b_even_scanline = i_y_offset % 2;
362 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
363 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
364 p_filter->fmt_out.video.i_x_offset +
365 p_dst->p[Y_PLANE].i_pitch *
366 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
367 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
368 p_filter->fmt_out.video.i_x_offset/2 +
369 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
370 p_dst->p[U_PLANE].i_pitch;
371 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
372 p_filter->fmt_out.video.i_x_offset/2 +
373 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
374 p_dst->p[V_PLANE].i_pitch;
376 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
377 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
378 p_filter->fmt_out.video.i_x_offset +
379 p_dst_orig->p[Y_PLANE].i_pitch *
380 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
381 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
382 p_filter->fmt_out.video.i_x_offset/2 +
383 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
384 p_dst_orig->p[U_PLANE].i_pitch;
385 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
386 p_filter->fmt_out.video.i_x_offset/2 +
387 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
388 p_dst_orig->p[V_PLANE].i_pitch;
390 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
391 p_src2_y = p_src->p[Y_PLANE].p_pixels +
392 p_filter->fmt_in.video.i_x_offset +
393 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
394 p_src2_u = p_src->p[U_PLANE].p_pixels +
395 p_filter->fmt_in.video.i_x_offset/2 +
396 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
397 p_src2_v = p_src->p[V_PLANE].p_pixels +
398 p_filter->fmt_in.video.i_x_offset/2 +
399 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
401 p_trans = p_src->p[A_PLANE].p_pixels +
402 p_filter->fmt_in.video.i_x_offset +
403 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
405 #define MAX_TRANS 255
408 /* Draw until we reach the bottom of the subtitle */
409 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
410 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
411 p_src2_y += i_src2_pitch,
412 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
413 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
414 p_src2_u += i_src2_pitch,
415 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
416 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
417 p_src2_v += i_src2_pitch )
419 b_even_scanline = !b_even_scanline;
421 /* Draw until we reach the end of the line */
422 for( i_x = 0; i_x < i_width; i_x++ )
425 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
428 /* Completely transparent. Don't change pixel */
431 else if( i_trans == MAX_TRANS )
433 /* Completely opaque. Completely overwrite underlying pixel */
434 p_dst_y[i_x] = p_src2_y[i_x];
436 if( b_even_scanline && i_x % 2 == 0 )
438 p_dst_u[i_x/2] = p_src2_u[i_x];
439 p_dst_v[i_x/2] = p_src2_v[i_x];
445 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
446 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
449 if( b_even_scanline && i_x % 2 == 0 )
451 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
452 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
454 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
455 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
467 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
468 picture_t *p_dst_orig, picture_t *p_src,
469 int i_x_offset, int i_y_offset,
470 int i_width, int i_height, int i_alpha )
472 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
473 uint8_t *p_dst, *p_src1, *p_src2_y;
474 uint8_t *p_src2_u, *p_src2_v;
476 int i_x, i_y, i_pix_pitch, i_trans = 0;
479 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
480 i_dst_pitch = p_dst_pic->p->i_pitch;
481 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
482 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
483 p_dst_pic->p->i_pitch *
484 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
486 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
487 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
488 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
489 p_dst_orig->p->i_pitch *
490 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
492 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
493 p_src2_y = p_src->p[Y_PLANE].p_pixels +
494 p_filter->fmt_in.video.i_x_offset +
495 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
496 p_src2_u = p_src->p[U_PLANE].p_pixels +
497 p_filter->fmt_in.video.i_x_offset/2 +
498 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
499 p_src2_v = p_src->p[V_PLANE].p_pixels +
500 p_filter->fmt_in.video.i_x_offset/2 +
501 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
503 p_trans = p_src->p[A_PLANE].p_pixels +
504 p_filter->fmt_in.video.i_x_offset +
505 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
507 #define MAX_TRANS 255
510 /* Draw until we reach the bottom of the subtitle */
511 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
512 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
513 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
514 p_src2_v += i_src2_pitch )
516 /* Draw until we reach the end of the line */
517 for( i_x = 0; i_x < i_width; i_x++ )
520 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
523 /* Completely transparent. Don't change pixel */
526 else if( i_trans == MAX_TRANS )
528 /* Completely opaque. Completely overwrite underlying pixel */
529 yuv_to_rgb( &r, &g, &b,
530 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
532 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
537 /* FIXME: do the blending */
538 yuv_to_rgb( &r, &g, &b,
539 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
541 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
551 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
552 picture_t *p_dst_orig, picture_t *p_src,
553 int i_x_offset, int i_y_offset,
554 int i_width, int i_height, int i_alpha )
556 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
557 uint8_t *p_dst, *p_src1, *p_src2_y;
558 uint8_t *p_src2_u, *p_src2_v;
560 int i_x, i_y, i_pix_pitch, i_trans = 0;
563 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
564 i_dst_pitch = p_dst_pic->p->i_pitch;
565 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
566 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
567 p_dst_pic->p->i_pitch *
568 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
570 i_src1_pitch = p_dst_orig->p->i_pitch;
571 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
572 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
573 p_dst_orig->p->i_pitch *
574 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
576 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
577 p_src2_y = p_src->p[Y_PLANE].p_pixels +
578 p_filter->fmt_in.video.i_x_offset +
579 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
580 p_src2_u = p_src->p[U_PLANE].p_pixels +
581 p_filter->fmt_in.video.i_x_offset/2 +
582 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
583 p_src2_v = p_src->p[V_PLANE].p_pixels +
584 p_filter->fmt_in.video.i_x_offset/2 +
585 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
587 p_trans = p_src->p[A_PLANE].p_pixels +
588 p_filter->fmt_in.video.i_x_offset +
589 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
591 #define MAX_TRANS 255
594 if( (i_pix_pitch == 4)
595 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
599 ** if picture pixels are 32 bits long and lines addresses are 32 bit
600 ** aligned, optimize rendering
602 uint32_t *p32_dst = (uint32_t *)p_dst;
603 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
604 uint32_t *p32_src1 = (uint32_t *)p_src1;
605 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
607 int i_rshift, i_gshift, i_bshift;
608 uint32_t i_rmask, i_gmask, i_bmask;
610 if( p_dst_pic->p_heap )
612 i_rmask = p_dst_pic->p_heap->i_rmask;
613 i_gmask = p_dst_pic->p_heap->i_gmask;
614 i_bmask = p_dst_pic->p_heap->i_bmask;
615 i_rshift = p_dst_pic->p_heap->i_lrshift;
616 i_gshift = p_dst_pic->p_heap->i_lgshift;
617 i_bshift = p_dst_pic->p_heap->i_lbshift;
621 i_rmask = p_dst_pic->format.i_rmask;
622 i_gmask = p_dst_pic->format.i_gmask;
623 i_bmask = p_dst_pic->format.i_bmask;
625 if( (i_rmask == 0x00FF0000)
626 && (i_gmask == 0x0000FF00)
627 && (i_bmask == 0x000000FF) )
629 /* X8R8G8B8 pixel layout */
634 else if( (i_rmask == 0xFF000000)
635 && (i_gmask == 0x00FF0000)
636 && (i_bmask == 0x0000FF00) )
638 /* R8G8B8X8 pixel layout */
648 /* Draw until we reach the bottom of the subtitle */
649 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
650 p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
651 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
652 p_src2_v += i_src2_pitch )
654 /* Draw until we reach the end of the line */
655 for( i_x = 0; i_x < i_width; i_x++ )
658 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
661 /* Completely transparent. Don't change pixel */
664 else if( i_trans == MAX_TRANS )
666 /* Completely opaque. Completely overwrite underlying pixel */
667 yuv_to_rgb( &r, &g, &b,
668 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
670 p32_dst[i_x] = (r<<i_rshift)
677 uint32_t i_pix_src1 = p32_src1[i_x];
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_trans +
682 (uint16_t)((i_pix_src1 & i_rmask)>>i_rshift) *
683 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_rshift
685 (uint16_t)((i_pix_src1 & i_gmask)>>i_gshift) *
686 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_gshift
688 (uint16_t)((i_pix_src1 & i_bmask)>>i_bshift) *
689 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_bshift;
696 int i_rindex, i_bindex, i_gindex;
697 uint32_t i_rmask, i_gmask, i_bmask;
701 i_rmask = p_dst_pic->format.i_rmask;
702 i_gmask = p_dst_pic->format.i_gmask;
703 i_bmask = p_dst_pic->format.i_bmask;
706 ** quick and dirty way to get byte index from mask
707 ** will only work correctly if mask are 8 bit aligned
708 ** and are 8 bit long
710 #ifdef WORDS_BIGENDIAN
711 i_rindex = ((i_rmask>>16) & 1)
714 i_gindex = ((i_gmask>>16) & 1)
717 i_bindex = ((i_bmask>>16) & 1)
721 i_rindex = ((i_rmask>>24) & 3)
722 | ((i_rmask>>16) & 2)
723 | ((i_rmask>>8) & 1);
724 i_gindex = ((i_gmask>>24) & 3)
725 | ((i_gmask>>16) & 2)
726 | ((i_gmask>>8) & 1);
727 i_bindex = ((i_bmask>>24) & 3)
728 | ((i_bmask>>16) & 2)
729 | ((i_bmask>>8) & 1);
732 /* Draw until we reach the bottom of the subtitle */
733 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
734 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
735 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
736 p_src2_v += i_src2_pitch )
738 /* Draw until we reach the end of the line */
739 for( i_x = 0; i_x < i_width; i_x++ )
742 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
745 /* Completely transparent. Don't change pixel */
750 int i_pos = i_x * i_pix_pitch;
751 if( i_trans == MAX_TRANS )
754 /* Completely opaque. Completely overwrite underlying pixel */
755 yuv_to_rgb( &r, &g, &b,
756 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
758 p_dst[i_pos + i_rindex ] = r;
759 p_dst[i_pos + i_gindex ] = g;
760 p_dst[i_pos + i_bindex ] = b;
764 int i_rpos = i_pos + i_rindex;
765 int i_gpos = i_pos + i_gindex;
766 int i_bpos = i_pos + i_bindex;
769 yuv_to_rgb( &r, &g, &b,
770 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
772 p_dst[i_rpos] = ( r * i_trans +
773 (uint16_t)p_src1[i_rpos] *
774 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
775 p_dst[i_gpos] = ( r * i_trans +
776 (uint16_t)p_src1[i_gpos] *
777 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
778 p_dst[i_bpos] = ( r * i_trans +
779 (uint16_t)p_src1[i_gpos] *
780 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
793 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
794 picture_t *p_dst_orig, picture_t *p_src,
795 int i_x_offset, int i_y_offset,
796 int i_width, int i_height, int i_alpha )
798 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
799 uint8_t *p_dst, *p_src1, *p_src2_y;
800 uint8_t *p_src2_u, *p_src2_v;
802 int i_x, i_y, i_pix_pitch, i_trans = 0;
803 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
804 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
806 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
812 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
818 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
826 i_dst_pitch = p_dst_pic->p->i_pitch;
827 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
828 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
829 p_dst_pic->p->i_pitch *
830 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
832 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
833 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
834 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
835 p_dst_orig->p->i_pitch *
836 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
838 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
839 p_src2_y = p_src->p[Y_PLANE].p_pixels +
840 p_filter->fmt_in.video.i_x_offset +
841 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
842 p_src2_u = p_src->p[U_PLANE].p_pixels +
843 p_filter->fmt_in.video.i_x_offset/2 +
844 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
845 p_src2_v = p_src->p[V_PLANE].p_pixels +
846 p_filter->fmt_in.video.i_x_offset/2 +
847 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
849 p_trans = p_src->p[A_PLANE].p_pixels +
850 p_filter->fmt_in.video.i_x_offset +
851 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
853 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
855 #define MAX_TRANS 255
858 /* Draw until we reach the bottom of the subtitle */
859 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
860 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
861 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
862 p_src2_v += i_src2_pitch )
864 /* Draw until we reach the end of the line */
865 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
867 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
870 /* Completely transparent. Don't change pixel */
872 else if( i_trans == MAX_TRANS )
874 /* Completely opaque. Completely overwrite underlying pixel */
875 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
879 if( p_trans[i_x+1] > 0xaa )
881 p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
882 p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
886 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
887 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
894 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_trans +
895 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
902 if( p_trans[i_x+1] > 0xaa )
904 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
905 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
912 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
913 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
915 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
916 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
928 /***********************************************************************
930 ***********************************************************************/
931 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
932 picture_t *p_dst_orig, picture_t *p_src,
933 int i_x_offset, int i_y_offset,
934 int i_width, int i_height, int i_alpha )
936 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
937 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
938 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
939 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
941 bool b_even_scanline = i_y_offset % 2;
943 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
944 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
945 p_filter->fmt_out.video.i_x_offset +
946 p_dst->p[Y_PLANE].i_pitch *
947 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
948 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
949 p_filter->fmt_out.video.i_x_offset/2 +
950 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
951 p_dst->p[U_PLANE].i_pitch;
952 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
953 p_filter->fmt_out.video.i_x_offset/2 +
954 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
955 p_dst->p[V_PLANE].i_pitch;
957 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
958 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
959 p_filter->fmt_out.video.i_x_offset +
960 p_dst_orig->p[Y_PLANE].i_pitch *
961 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
962 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
963 p_filter->fmt_out.video.i_x_offset/2 +
964 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
965 p_dst_orig->p[U_PLANE].i_pitch;
966 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
967 p_filter->fmt_out.video.i_x_offset/2 +
968 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
969 p_dst_orig->p[V_PLANE].i_pitch;
971 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
972 p_src2_y = p_src->p[Y_PLANE].p_pixels +
973 p_filter->fmt_in.video.i_x_offset +
974 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
975 p_src2_u = p_src->p[U_PLANE].p_pixels +
976 p_filter->fmt_in.video.i_x_offset/2 +
977 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
978 p_src2_v = p_src->p[V_PLANE].p_pixels +
979 p_filter->fmt_in.video.i_x_offset/2 +
980 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
982 #define MAX_TRANS 255
985 /* Draw until we reach the bottom of the subtitle */
986 for( i_y = 0; i_y < i_height; i_y++,
987 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
988 p_src2_y += i_src2_pitch )
990 if( b_even_scanline )
992 p_dst_u += i_dst_pitch/2;
993 p_dst_v += i_dst_pitch/2;
994 p_src1_u += i_src1_pitch/2;
995 p_src1_v += i_src1_pitch/2;
997 b_even_scanline = !b_even_scanline;
999 /* Draw until we reach the end of the line */
1000 for( i_x = 0; i_x < i_width; i_x++ )
1002 if( i_alpha == MAX_TRANS )
1004 /* Completely opaque. Completely overwrite underlying pixel */
1005 p_dst_y[i_x] = p_src2_y[i_x];
1007 if( b_even_scanline && i_x % 2 == 0 )
1009 p_dst_u[i_x/2] = p_src2_u[i_x/2];
1010 p_dst_v[i_x/2] = p_src2_v[i_x/2];
1016 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1017 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_alpha) )
1020 if( b_even_scanline && i_x % 2 == 0 )
1022 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x/2] * i_alpha +
1023 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_alpha) )
1025 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x/2] * i_alpha +
1026 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_alpha) )
1032 p_src2_u += i_src2_pitch/2;
1033 p_src2_v += i_src2_pitch/2;
1042 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
1043 picture_t *p_dst_orig, picture_t *p_src,
1044 int i_x_offset, int i_y_offset,
1045 int i_width, int i_height )
1047 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1048 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
1049 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
1050 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
1052 bool b_even_scanline = i_y_offset % 2;
1054 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1055 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1056 p_filter->fmt_out.video.i_x_offset +
1057 p_dst->p[Y_PLANE].i_pitch *
1058 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1059 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1060 p_filter->fmt_out.video.i_x_offset/2 +
1061 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1062 p_dst->p[U_PLANE].i_pitch;
1063 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1064 p_filter->fmt_out.video.i_x_offset/2 +
1065 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1066 p_dst->p[V_PLANE].i_pitch;
1068 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1069 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1070 p_filter->fmt_out.video.i_x_offset +
1071 p_dst_orig->p[Y_PLANE].i_pitch *
1072 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1073 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1074 p_filter->fmt_out.video.i_x_offset/2 +
1075 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1076 p_dst_orig->p[U_PLANE].i_pitch;
1077 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1078 p_filter->fmt_out.video.i_x_offset/2 +
1079 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1080 p_dst_orig->p[V_PLANE].i_pitch;
1082 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1083 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1084 p_filter->fmt_in.video.i_x_offset +
1085 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1086 p_src2_u = p_src->p[U_PLANE].p_pixels +
1087 p_filter->fmt_in.video.i_x_offset/2 +
1088 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1089 p_src2_v = p_src->p[V_PLANE].p_pixels +
1090 p_filter->fmt_in.video.i_x_offset/2 +
1091 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1095 /* Draw until we reach the bottom of the subtitle */
1096 for( i_y = 0; i_y < i_height; i_y++,
1097 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1098 p_src2_y += i_src2_pitch )
1100 /* Completely opaque. Completely overwrite underlying pixel */
1101 vlc_memcpy( p_dst_y, p_src2_y, i_width );
1102 if( b_even_scanline )
1104 p_dst_u += i_dst_pitch/2;
1105 p_dst_v += i_dst_pitch/2;
1106 p_src1_u += i_src1_pitch/2;
1107 p_src1_v += i_src1_pitch/2;
1111 vlc_memcpy( p_dst_u, p_src2_u, i_width/2 );
1112 vlc_memcpy( p_dst_v, p_src2_v, i_width/2 );
1114 b_even_scanline = !b_even_scanline;
1117 p_src2_u += i_src2_pitch/2;
1118 p_src2_v += i_src2_pitch/2;
1125 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1126 picture_t *p_dst_orig, picture_t *p_src,
1127 int i_x_offset, int i_y_offset,
1128 int i_width, int i_height, int i_alpha )
1130 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1131 uint8_t *p_dst, *p_src1, *p_src2_y;
1132 uint8_t *p_src2_u, *p_src2_v;
1133 int i_x, i_y, i_pix_pitch;
1136 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1137 i_dst_pitch = p_dst_pic->p->i_pitch;
1138 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1139 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1140 p_dst_pic->p->i_pitch *
1141 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1143 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1144 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1145 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1146 p_dst_orig->p->i_pitch *
1147 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1149 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1150 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1151 p_filter->fmt_in.video.i_x_offset +
1152 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1153 p_src2_u = p_src->p[U_PLANE].p_pixels +
1154 p_filter->fmt_in.video.i_x_offset/2 +
1155 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1156 p_src2_v = p_src->p[V_PLANE].p_pixels +
1157 p_filter->fmt_in.video.i_x_offset/2 +
1158 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1160 #define MAX_TRANS 255
1161 #define TRANS_BITS 8
1163 /* Draw until we reach the bottom of the subtitle */
1164 for( i_y = 0; i_y < i_height; i_y++,
1165 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1166 p_src2_y += i_src2_pitch )
1168 /* Draw until we reach the end of the line */
1169 for( i_x = 0; i_x < i_width; i_x++ )
1171 if( i_alpha == MAX_TRANS )
1173 /* Completely opaque. Completely overwrite underlying pixel */
1174 yuv_to_rgb( &r, &g, &b,
1175 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1177 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1182 /* FIXME: do the blending */
1183 yuv_to_rgb( &r, &g, &b,
1184 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1186 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1190 p_src2_u += i_src2_pitch/2;
1191 p_src2_v += i_src2_pitch/2;
1201 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1202 picture_t *p_dst_orig, picture_t *p_src,
1203 int i_x_offset, int i_y_offset,
1204 int i_width, int i_height, int i_alpha )
1206 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1207 uint8_t *p_dst, *p_src1, *p_src2_y;
1208 uint8_t *p_src2_u, *p_src2_v;
1209 int i_x, i_y, i_pix_pitch;
1212 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1213 i_dst_pitch = p_dst_pic->p->i_pitch;
1214 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1215 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1216 p_dst_pic->p->i_pitch *
1217 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1219 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1220 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1221 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1222 p_dst_orig->p->i_pitch *
1223 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1225 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1226 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1227 p_filter->fmt_in.video.i_x_offset +
1228 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1229 p_src2_u = p_src->p[U_PLANE].p_pixels +
1230 p_filter->fmt_in.video.i_x_offset/2 +
1231 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1232 p_src2_v = p_src->p[V_PLANE].p_pixels +
1233 p_filter->fmt_in.video.i_x_offset/2 +
1234 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1236 #define MAX_TRANS 255
1237 #define TRANS_BITS 8
1239 /* Draw until we reach the bottom of the subtitle */
1240 for( i_y = 0; i_y < i_height; i_y++,
1241 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1242 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1243 p_src2_v += i_src2_pitch )
1245 /* Draw until we reach the end of the line */
1246 for( i_x = 0; i_x < i_width; i_x++ )
1248 if( i_alpha == MAX_TRANS )
1250 /* Completely opaque. Completely overwrite underlying pixel */
1251 yuv_to_rgb( &r, &g, &b,
1252 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1254 p_dst[i_x * i_pix_pitch] = r;
1255 p_dst[i_x * i_pix_pitch + 1] = g;
1256 p_dst[i_x * i_pix_pitch + 2] = b;
1261 yuv_to_rgb( &r, &g, &b,
1262 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1264 p_dst[i_x * i_pix_pitch] = ( r * i_alpha +
1265 (uint16_t)p_src1[i_x * i_pix_pitch] *
1266 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1267 p_dst[i_x * i_pix_pitch + 1] = ( g * i_alpha +
1268 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1269 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1270 p_dst[i_x * i_pix_pitch + 2] = ( b * i_alpha +
1271 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1272 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1276 p_src2_u += i_src2_pitch/2;
1277 p_src2_v += i_src2_pitch/2;
1287 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1288 picture_t *p_dst_orig, picture_t *p_src,
1289 int i_x_offset, int i_y_offset,
1290 int i_width, int i_height, int i_alpha )
1292 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1293 uint8_t *p_dst, *p_src1, *p_src2_y;
1294 uint8_t *p_src2_u, *p_src2_v;
1295 int i_x, i_y, i_pix_pitch;
1296 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1297 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1299 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1305 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1311 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1319 i_dst_pitch = p_dst_pic->p->i_pitch;
1320 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1321 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1322 p_dst_pic->p->i_pitch *
1323 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1325 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1326 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1327 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1328 p_dst_orig->p->i_pitch *
1329 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1331 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1332 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1333 p_filter->fmt_in.video.i_x_offset +
1334 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1335 p_src2_u = p_src->p[U_PLANE].p_pixels +
1336 p_filter->fmt_in.video.i_x_offset/2 +
1337 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1338 p_src2_v = p_src->p[V_PLANE].p_pixels +
1339 p_filter->fmt_in.video.i_x_offset/2 +
1340 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1342 i_width &= ~1; /* Needs to be a multiple of 2 */
1344 #define MAX_TRANS 255
1345 #define TRANS_BITS 8
1347 /* Draw until we reach the bottom of the subtitle */
1348 for( i_y = 0; i_y < i_height; i_y++,
1349 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1350 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1351 p_src2_v += i_src2_pitch )
1353 /* Draw until we reach the end of the line */
1354 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1356 if( i_alpha == MAX_TRANS )
1358 /* Completely opaque. Completely overwrite underlying pixel */
1359 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
1363 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x/2];
1364 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x/2];
1370 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1371 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_alpha) )
1376 uint16_t i_u = p_src2_u[i_x/2];
1377 uint16_t i_v = p_src2_v[i_x/2];
1378 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_alpha +
1379 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_alpha) )
1381 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_alpha +
1382 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_alpha) )
1389 p_src2_u += i_src2_pitch/2;
1390 p_src2_v += i_src2_pitch/2;
1400 /***********************************************************************
1402 ***********************************************************************/
1403 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1404 picture_t *p_dst_orig, picture_t *p_src,
1405 int i_x_offset, int i_y_offset,
1406 int i_width, int i_height, int i_alpha )
1408 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1409 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1410 uint8_t *p_src1_u, *p_dst_u;
1411 uint8_t *p_src1_v, *p_dst_v;
1412 int i_x, i_y, i_trans;
1413 bool b_even_scanline = i_y_offset % 2;
1415 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1416 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1417 p_filter->fmt_out.video.i_x_offset +
1418 p_dst->p[Y_PLANE].i_pitch *
1419 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1420 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1421 p_filter->fmt_out.video.i_x_offset/2 +
1422 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1423 p_dst->p[U_PLANE].i_pitch;
1424 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1425 p_filter->fmt_out.video.i_x_offset/2 +
1426 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1427 p_dst->p[V_PLANE].i_pitch;
1429 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1430 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1431 p_filter->fmt_out.video.i_x_offset +
1432 p_dst_orig->p[Y_PLANE].i_pitch *
1433 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1434 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1435 p_filter->fmt_out.video.i_x_offset/2 +
1436 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1437 p_dst_orig->p[U_PLANE].i_pitch;
1438 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1439 p_filter->fmt_out.video.i_x_offset/2 +
1440 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1441 p_dst_orig->p[V_PLANE].i_pitch;
1443 i_src2_pitch = p_src->p->i_pitch;
1444 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1445 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1447 #define MAX_TRANS 255
1448 #define TRANS_BITS 8
1449 #define p_trans p_src2
1450 #define p_pal p_filter->fmt_in.video.p_palette->palette
1452 /* Draw until we reach the bottom of the subtitle */
1453 for( i_y = 0; i_y < i_height; i_y++,
1454 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1455 p_src2 += i_src2_pitch,
1456 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1457 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1458 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1459 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1461 b_even_scanline = !b_even_scanline;
1463 /* Draw until we reach the end of the line */
1464 for( i_x = 0; i_x < i_width; i_x++ )
1466 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1469 /* Completely transparent. Don't change pixel */
1472 else if( i_trans == MAX_TRANS )
1474 /* Completely opaque. Completely overwrite underlying pixel */
1475 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
1477 if( b_even_scanline && ((i_x % 2) == 0) )
1479 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
1480 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
1486 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
1487 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1490 if( b_even_scanline && ((i_x % 2) == 0) )
1492 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
1493 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1495 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
1496 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1510 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1511 picture_t *p_dst_orig, picture_t *p_src,
1512 int i_x_offset, int i_y_offset,
1513 int i_width, int i_height, int i_alpha )
1515 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1516 uint8_t *p_src1, *p_src2, *p_dst;
1517 int i_x, i_y, i_pix_pitch, i_trans;
1518 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1519 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1521 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1527 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1533 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1541 i_dst_pitch = p_dst_pic->p->i_pitch;
1542 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1543 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1544 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1546 i_src1_pitch = p_dst_orig->p->i_pitch;
1547 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1548 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1549 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1551 i_src2_pitch = p_src->p->i_pitch;
1552 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1553 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1555 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1557 #define MAX_TRANS 255
1558 #define TRANS_BITS 8
1559 #define p_trans p_src2
1560 #define p_pal p_filter->fmt_in.video.p_palette->palette
1562 /* Draw until we reach the bottom of the subtitle */
1563 for( i_y = 0; i_y < i_height; i_y++,
1564 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1566 /* Draw until we reach the end of the line */
1567 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1569 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1572 /* Completely transparent. Don't change pixel */
1574 else if( i_trans == MAX_TRANS )
1576 /* Completely opaque. Completely overwrite underlying pixel */
1577 p_dst[i_x * 2 + i_l_offset] = p_pal[p_src2[i_x]][0];
1581 if( p_trans[i_x+1] > 0xaa )
1583 p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1584 p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1588 p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1589 p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1596 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1597 i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1598 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1604 if( p_trans[i_x+1] > 0xaa )
1606 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1607 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1611 i_u = p_pal[p_src2[i_x]][1];
1612 i_v = p_pal[p_src2[i_x]][2];
1615 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1616 i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1617 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1618 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1619 i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1620 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1634 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1635 picture_t *p_dst_orig, picture_t *p_src,
1636 int i_x_offset, int i_y_offset,
1637 int i_width, int i_height, int i_alpha )
1639 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1640 uint8_t *p_src1, *p_src2, *p_dst;
1641 int i_x, i_y, i_pix_pitch, i_trans;
1643 video_palette_t rgbpalette;
1645 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1646 i_dst_pitch = p_dst_pic->p->i_pitch;
1647 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1648 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1649 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1651 i_src1_pitch = p_dst_orig->p->i_pitch;
1652 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1653 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1654 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1656 i_src2_pitch = p_src->p->i_pitch;
1657 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1658 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1660 #define MAX_TRANS 255
1661 #define TRANS_BITS 8
1662 #define p_trans p_src2
1663 #define p_pal p_filter->fmt_in.video.p_palette->palette
1664 #define rgbpal rgbpalette.palette
1666 /* Convert palette first */
1667 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1670 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1672 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1674 *(uint16_t *)rgbpal[i_y] =
1675 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1679 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1683 /* Draw until we reach the bottom of the subtitle */
1684 for( i_y = 0; i_y < i_height; i_y++,
1685 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1687 /* Draw until we reach the end of the line */
1688 for( i_x = 0; i_x < i_width; i_x++ )
1690 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1693 /* Completely transparent. Don't change pixel */
1696 else if( i_trans == MAX_TRANS ||
1697 p_filter->fmt_out.video.i_chroma ==
1698 VLC_FOURCC('R','V','1','6') )
1700 /* Completely opaque. Completely overwrite underlying pixel */
1701 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1702 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1703 if( p_filter->fmt_out.video.i_chroma !=
1704 VLC_FOURCC('R','V','1','6') )
1705 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1710 p_dst[i_x * i_pix_pitch] = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1711 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1712 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1713 p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1714 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1715 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1716 p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1717 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1718 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1731 /***********************************************************************
1733 ***********************************************************************/
1734 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1735 picture_t *p_dst_orig, picture_t *p_src,
1736 int i_x_offset, int i_y_offset,
1737 int i_width, int i_height, int i_alpha )
1739 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1740 uint8_t *p_src1_y, *p_dst_y;
1741 uint8_t *p_src1_u, *p_dst_u;
1742 uint8_t *p_src1_v, *p_dst_v;
1744 int i_x, i_y, i_trans;
1747 bool b_even_scanline = i_y_offset % 2;
1749 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1750 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1751 p_filter->fmt_out.video.i_x_offset +
1752 p_dst->p[Y_PLANE].i_pitch *
1753 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1754 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1755 p_filter->fmt_out.video.i_x_offset/2 +
1756 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1757 p_dst->p[U_PLANE].i_pitch;
1758 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1759 p_filter->fmt_out.video.i_x_offset/2 +
1760 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1761 p_dst->p[V_PLANE].i_pitch;
1763 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1764 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1765 p_filter->fmt_out.video.i_x_offset +
1766 p_dst_orig->p[Y_PLANE].i_pitch *
1767 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1768 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1769 p_filter->fmt_out.video.i_x_offset/2 +
1770 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1771 p_dst_orig->p[U_PLANE].i_pitch;
1772 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1773 p_filter->fmt_out.video.i_x_offset/2 +
1774 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1775 p_dst_orig->p[V_PLANE].i_pitch;
1777 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1778 i_src2_pitch = p_src->p->i_pitch;
1779 p_src2 = p_src->p->p_pixels +
1780 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1781 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1784 #define MAX_TRANS 255
1785 #define TRANS_BITS 8
1787 /* Draw until we reach the bottom of the subtitle */
1788 for( i_y = 0; i_y < i_height; i_y++,
1789 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1790 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1791 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1792 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1793 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1794 p_src2 += i_src2_pitch )
1796 b_even_scanline = !b_even_scanline;
1798 /* Draw until we reach the end of the line */
1799 for( i_x = 0; i_x < i_width; i_x++ )
1801 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1802 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1803 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1804 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1807 /* Completely transparent. Don't change pixel */
1810 else if( i_trans == MAX_TRANS )
1812 /* Completely opaque. Completely overwrite underlying pixel */
1813 rgb_to_yuv( &y, &u, &v, R, G, B );
1816 if( b_even_scanline && i_x % 2 == 0 )
1825 rgb_to_yuv( &y, &u, &v, R, G, B );
1826 p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1827 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1830 if( b_even_scanline && i_x % 2 == 0 )
1832 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1833 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1835 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1836 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1851 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1852 picture_t *p_dst_orig, picture_t *p_src,
1853 int i_x_offset, int i_y_offset,
1854 int i_width, int i_height, int i_alpha )
1856 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1857 uint8_t *p_dst, *p_src1, *p_src2;
1858 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1860 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1861 i_dst_pitch = p_dst_pic->p->i_pitch;
1862 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1863 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1864 p_dst_pic->p->i_pitch *
1865 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1867 i_src1_pitch = p_dst_orig->p->i_pitch;
1868 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1869 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1870 p_dst_orig->p->i_pitch *
1871 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1873 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1874 i_src2_pitch = p_src->p->i_pitch;
1875 p_src2 = p_src->p->p_pixels +
1876 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1877 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1879 #define MAX_TRANS 255
1880 #define TRANS_BITS 8
1882 /* Draw until we reach the bottom of the subtitle */
1883 for( i_y = 0; i_y < i_height; i_y++,
1884 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1886 /* Draw until we reach the end of the line */
1887 for( i_x = 0; i_x < i_width; i_x++ )
1889 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1890 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1891 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1892 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1895 /* Completely transparent. Don't change pixel */
1898 else if( i_trans == MAX_TRANS )
1900 /* Completely opaque. Completely overwrite underlying pixel */
1901 p_dst[i_x * i_pix_pitch + 0] = R;
1902 p_dst[i_x * i_pix_pitch + 1] = G;
1903 p_dst[i_x * i_pix_pitch + 2] = B;
1908 p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1909 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1910 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1911 p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1912 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1913 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1914 p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1915 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1916 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1929 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1930 picture_t *p_dst_orig, picture_t *p_src,
1931 int i_x_offset, int i_y_offset,
1932 int i_width, int i_height, int i_alpha )
1934 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1935 uint8_t *p_dst, *p_src1, *p_src2;
1936 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1939 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1940 i_dst_pitch = p_dst_pic->p->i_pitch;
1941 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1942 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1943 p_dst_pic->p->i_pitch *
1944 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1946 i_src1_pitch = p_dst_orig->p->i_pitch;
1947 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1948 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1949 p_dst_orig->p->i_pitch *
1950 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1952 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1953 i_src2_pitch = p_src->p->i_pitch;
1954 p_src2 = p_src->p->p_pixels +
1955 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1956 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1958 #define MAX_TRANS 255
1959 #define TRANS_BITS 8
1961 /* Draw until we reach the bottom of the subtitle */
1962 for( i_y = 0; i_y < i_height; i_y++,
1963 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1965 /* Draw until we reach the end of the line */
1966 for( i_x = 0; i_x < i_width; i_x++ )
1968 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1969 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1970 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1971 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1974 /* Completely transparent. Don't change pixel */
1977 else if( i_trans == MAX_TRANS )
1979 /* Completely opaque. Completely overwrite underlying pixel */
1980 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1985 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1986 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1987 ( ( ( (R >> 3)*i_trans
1988 + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1989 >> TRANS_BITS ) << 11 )
1990 | ( ( ( (G >> 2)*i_trans
1991 + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1992 >> TRANS_BITS ) << 5 )
1993 | ( ( ( (B >> 3)*i_trans
1994 + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
2008 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
2009 picture_t *p_dst_orig, picture_t *p_src,
2010 int i_x_offset, int i_y_offset,
2011 int i_width, int i_height, int i_alpha )
2013 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
2014 uint8_t *p_dst, *p_src1, *p_src2;
2016 int i_x, i_y, i_pix_pitch, i_trans;
2017 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
2018 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
2021 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
2027 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
2033 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
2041 i_dst_pitch = p_dst_pic->p->i_pitch;
2042 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
2043 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2044 p_dst_pic->p->i_pitch *
2045 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2047 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
2048 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
2049 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2050 p_dst_orig->p->i_pitch *
2051 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2053 i_src_pix_pitch = p_src->p->i_pixel_pitch;
2054 i_src2_pitch = p_src->p->i_pitch;
2055 p_src2 = p_src->p->p_pixels +
2056 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
2057 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
2059 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
2061 #define MAX_TRANS 255
2062 #define TRANS_BITS 8
2064 /* Draw until we reach the bottom of the subtitle */
2065 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
2066 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
2067 p_src2 += i_src2_pitch )
2069 /* Draw until we reach the end of the line */
2070 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
2072 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
2073 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
2074 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
2075 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
2078 /* Completely transparent. Don't change pixel */
2080 else if( i_trans == MAX_TRANS )
2082 /* Completely opaque. Completely overwrite underlying pixel */
2083 rgb_to_yuv( &y, &u, &v, R, G, B );
2084 p_dst[i_x * 2 + i_l_offset] = y;
2088 p_dst[i_x * 2 + i_u_offset] = u;
2089 p_dst[i_x * 2 + i_v_offset] = v;
2095 rgb_to_yuv( &y, &u, &v, R, G, B );
2096 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)y * i_trans +
2097 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
2102 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
2103 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
2105 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
2106 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )