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 #define MAX_TRANS 255
327 static inline int vlc_blend( int v1, int v2, int a )
329 /* TODO bench if the tests really increase speed */
332 else if( a == MAX_TRANS )
334 return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
337 static inline void yuv_to_rgb( int *r, int *g, int *b,
338 uint8_t y1, uint8_t u1, uint8_t v1 )
340 /* macros used for YUV pixel conversions */
341 # define SCALEBITS 10
342 # define ONE_HALF (1 << (SCALEBITS - 1))
343 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
345 int y, cb, cr, r_add, g_add, b_add;
349 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
350 g_add = - FIX(0.34414*255.0/224.0) * cb
351 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
352 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
353 y = (y1 - 16) * FIX(255.0/219.0);
354 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
355 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
356 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
362 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
363 int r, int g, int b )
365 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
366 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
367 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
370 /***********************************************************************
372 ***********************************************************************/
373 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
374 picture_t *p_dst_orig, picture_t *p_src,
375 int i_x_offset, int i_y_offset,
376 int i_width, int i_height, int i_alpha )
378 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
379 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
380 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
381 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
383 int i_x, i_y, i_trans = 0;
384 bool b_even_scanline = i_y_offset % 2;
386 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
387 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
388 p_filter->fmt_out.video.i_x_offset +
389 p_dst->p[Y_PLANE].i_pitch *
390 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
391 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
392 p_filter->fmt_out.video.i_x_offset/2 +
393 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
394 p_dst->p[U_PLANE].i_pitch;
395 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
396 p_filter->fmt_out.video.i_x_offset/2 +
397 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
398 p_dst->p[V_PLANE].i_pitch;
400 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
401 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
402 p_filter->fmt_out.video.i_x_offset +
403 p_dst_orig->p[Y_PLANE].i_pitch *
404 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
405 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
406 p_filter->fmt_out.video.i_x_offset/2 +
407 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
408 p_dst_orig->p[U_PLANE].i_pitch;
409 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
410 p_filter->fmt_out.video.i_x_offset/2 +
411 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
412 p_dst_orig->p[V_PLANE].i_pitch;
414 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
415 p_src2_y = p_src->p[Y_PLANE].p_pixels +
416 p_filter->fmt_in.video.i_x_offset +
417 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
418 p_src2_u = p_src->p[U_PLANE].p_pixels +
419 p_filter->fmt_in.video.i_x_offset/2 +
420 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
421 p_src2_v = p_src->p[V_PLANE].p_pixels +
422 p_filter->fmt_in.video.i_x_offset/2 +
423 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
425 p_trans = p_src->p[A_PLANE].p_pixels +
426 p_filter->fmt_in.video.i_x_offset +
427 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
429 /* Draw until we reach the bottom of the subtitle */
430 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
431 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
432 p_src2_y += i_src2_pitch,
433 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
434 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
435 p_src2_u += i_src2_pitch,
436 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
437 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
438 p_src2_v += i_src2_pitch )
440 b_even_scanline = !b_even_scanline;
442 /* Draw until we reach the end of the line */
443 for( i_x = 0; i_x < i_width; i_x++ )
446 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
452 p_dst_y[i_x] = vlc_blend( p_src2_y[i_x], p_src1_y[i_x], i_trans );
453 if( b_even_scanline && i_x % 2 == 0 )
455 p_dst_u[i_x/2] = vlc_blend( p_src2_u[i_x], p_src1_u[i_x/2], i_trans );
456 p_dst_v[i_x/2] = vlc_blend( p_src2_v[i_x], p_src1_v[i_x/2], i_trans );
462 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
463 picture_t *p_dst_orig, picture_t *p_src,
464 int i_x_offset, int i_y_offset,
465 int i_width, int i_height, int i_alpha )
467 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
468 uint8_t *p_dst, *p_src1, *p_src2_y;
469 uint8_t *p_src2_u, *p_src2_v;
471 int i_x, i_y, i_pix_pitch, i_trans = 0;
474 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
475 i_dst_pitch = p_dst_pic->p->i_pitch;
476 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
477 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
478 p_dst_pic->p->i_pitch *
479 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
481 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
482 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
483 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
484 p_dst_orig->p->i_pitch *
485 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
487 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
488 p_src2_y = p_src->p[Y_PLANE].p_pixels +
489 p_filter->fmt_in.video.i_x_offset +
490 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
491 p_src2_u = p_src->p[U_PLANE].p_pixels +
492 p_filter->fmt_in.video.i_x_offset/2 +
493 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
494 p_src2_v = p_src->p[V_PLANE].p_pixels +
495 p_filter->fmt_in.video.i_x_offset/2 +
496 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
498 p_trans = p_src->p[A_PLANE].p_pixels +
499 p_filter->fmt_in.video.i_x_offset +
500 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
502 /* Draw until we reach the bottom of the subtitle */
503 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
504 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
505 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
506 p_src2_v += i_src2_pitch )
508 /* Draw until we reach the end of the line */
509 for( i_x = 0; i_x < i_width; i_x++ )
512 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
517 /* FIXME: do the blending
518 * FIXME use rgb shift (when present) */
519 yuv_to_rgb( &r, &g, &b,
520 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
522 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
527 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
528 picture_t *p_dst_orig, picture_t *p_src,
529 int i_x_offset, int i_y_offset,
530 int i_width, int i_height, int i_alpha )
532 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
533 uint8_t *p_dst, *p_src1, *p_src2_y;
534 uint8_t *p_src2_u, *p_src2_v;
536 int i_x, i_y, i_pix_pitch, i_trans = 0;
539 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
540 i_dst_pitch = p_dst_pic->p->i_pitch;
541 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
542 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
543 p_dst_pic->p->i_pitch *
544 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
546 i_src1_pitch = p_dst_orig->p->i_pitch;
547 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
548 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
549 p_dst_orig->p->i_pitch *
550 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
552 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
553 p_src2_y = p_src->p[Y_PLANE].p_pixels +
554 p_filter->fmt_in.video.i_x_offset +
555 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
556 p_src2_u = p_src->p[U_PLANE].p_pixels +
557 p_filter->fmt_in.video.i_x_offset/2 +
558 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
559 p_src2_v = p_src->p[V_PLANE].p_pixels +
560 p_filter->fmt_in.video.i_x_offset/2 +
561 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
563 p_trans = p_src->p[A_PLANE].p_pixels +
564 p_filter->fmt_in.video.i_x_offset +
565 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
567 if( (i_pix_pitch == 4)
568 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
572 ** if picture pixels are 32 bits long and lines addresses are 32 bit
573 ** aligned, optimize rendering
575 uint32_t *p32_dst = (uint32_t *)p_dst;
576 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
577 uint32_t *p32_src1 = (uint32_t *)p_src1;
578 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
580 int i_rshift, i_gshift, i_bshift;
581 uint32_t i_rmask, i_gmask, i_bmask;
583 if( p_dst_pic->p_heap )
585 i_rmask = p_dst_pic->p_heap->i_rmask;
586 i_gmask = p_dst_pic->p_heap->i_gmask;
587 i_bmask = p_dst_pic->p_heap->i_bmask;
588 i_rshift = p_dst_pic->p_heap->i_lrshift;
589 i_gshift = p_dst_pic->p_heap->i_lgshift;
590 i_bshift = p_dst_pic->p_heap->i_lbshift;
594 i_rmask = p_dst_pic->format.i_rmask;
595 i_gmask = p_dst_pic->format.i_gmask;
596 i_bmask = p_dst_pic->format.i_bmask;
598 if( (i_rmask == 0x00FF0000)
599 && (i_gmask == 0x0000FF00)
600 && (i_bmask == 0x000000FF) )
602 /* X8R8G8B8 pixel layout */
607 else if( (i_rmask == 0xFF000000)
608 && (i_gmask == 0x00FF0000)
609 && (i_bmask == 0x0000FF00) )
611 /* R8G8B8X8 pixel layout */
621 /* Draw until we reach the bottom of the subtitle */
622 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
623 p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
624 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
625 p_src2_v += i_src2_pitch )
627 /* Draw until we reach the end of the line */
628 for( i_x = 0; i_x < i_width; i_x++ )
631 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
635 if( i_trans == MAX_TRANS )
637 /* Completely opaque. Completely overwrite underlying pixel */
638 yuv_to_rgb( &r, &g, &b,
639 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
641 p32_dst[i_x] = (r<<i_rshift) |
648 uint32_t i_pix_src1 = p32_src1[i_x];
649 yuv_to_rgb( &r, &g, &b,
650 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
652 p32_dst[i_x] = ( vlc_blend( r, (i_pix_src1 & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
653 ( vlc_blend( g, (i_pix_src1 & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
654 ( vlc_blend( b, (i_pix_src1 & i_bmask)>>i_bshift, i_trans ) << i_bshift );
661 int i_rindex, i_bindex, i_gindex;
662 uint32_t i_rmask, i_gmask, i_bmask;
666 i_rmask = p_dst_pic->format.i_rmask;
667 i_gmask = p_dst_pic->format.i_gmask;
668 i_bmask = p_dst_pic->format.i_bmask;
671 ** quick and dirty way to get byte index from mask
672 ** will only work correctly if mask are 8 bit aligned
673 ** and are 8 bit long
675 #ifdef WORDS_BIGENDIAN
676 i_rindex = ((i_rmask>>16) & 1)
679 i_gindex = ((i_gmask>>16) & 1)
682 i_bindex = ((i_bmask>>16) & 1)
686 i_rindex = ((i_rmask>>24) & 3)
687 | ((i_rmask>>16) & 2)
688 | ((i_rmask>>8) & 1);
689 i_gindex = ((i_gmask>>24) & 3)
690 | ((i_gmask>>16) & 2)
691 | ((i_gmask>>8) & 1);
692 i_bindex = ((i_bmask>>24) & 3)
693 | ((i_bmask>>16) & 2)
694 | ((i_bmask>>8) & 1);
697 /* Draw until we reach the bottom of the subtitle */
698 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
699 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
700 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
701 p_src2_v += i_src2_pitch )
703 /* Draw until we reach the end of the line */
704 for( i_x = 0; i_x < i_width; i_x++ )
707 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
711 const int i_pos = i_x * i_pix_pitch;
712 if( i_trans == MAX_TRANS )
715 /* Completely opaque. Completely overwrite underlying pixel */
716 yuv_to_rgb( &r, &g, &b,
717 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
719 p_dst[i_pos + i_rindex ] = r;
720 p_dst[i_pos + i_gindex ] = g;
721 p_dst[i_pos + i_bindex ] = b;
725 int i_rpos = i_pos + i_rindex;
726 int i_gpos = i_pos + i_gindex;
727 int i_bpos = i_pos + i_bindex;
730 yuv_to_rgb( &r, &g, &b,
731 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
733 p_dst[i_rpos] = vlc_blend( r, p_src1[i_rpos], i_trans );
734 p_dst[i_gpos] = vlc_blend( g, p_src1[i_gpos], i_trans );
735 p_dst[i_bpos] = vlc_blend( b, p_src1[i_gpos], i_trans );
742 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
743 picture_t *p_dst_orig, picture_t *p_src,
744 int i_x_offset, int i_y_offset,
745 int i_width, int i_height, int i_alpha )
747 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
748 uint8_t *p_dst, *p_src1, *p_src2_y;
749 uint8_t *p_src2_u, *p_src2_v;
751 int i_x, i_y, i_pix_pitch, i_trans = 0;
752 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
753 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
755 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
761 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
767 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
775 i_dst_pitch = p_dst_pic->p->i_pitch;
776 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
777 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
778 p_dst_pic->p->i_pitch *
779 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
781 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
782 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
783 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
784 p_dst_orig->p->i_pitch *
785 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
787 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
788 p_src2_y = p_src->p[Y_PLANE].p_pixels +
789 p_filter->fmt_in.video.i_x_offset +
790 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
791 p_src2_u = p_src->p[U_PLANE].p_pixels +
792 p_filter->fmt_in.video.i_x_offset/2 +
793 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
794 p_src2_v = p_src->p[V_PLANE].p_pixels +
795 p_filter->fmt_in.video.i_x_offset/2 +
796 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
798 p_trans = p_src->p[A_PLANE].p_pixels +
799 p_filter->fmt_in.video.i_x_offset +
800 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
802 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
804 /* Draw until we reach the bottom of the subtitle */
805 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
806 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
807 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
808 p_src2_v += i_src2_pitch )
810 /* Draw until we reach the end of the line */
811 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
813 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
818 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_trans );
823 /* FIXME what's with 0xaa ? */
824 if( p_trans[i_x+1] > 0xaa )
826 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
827 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
834 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_trans );
835 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_trans );
840 /***********************************************************************
842 ***********************************************************************/
843 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
844 picture_t *p_dst_orig, picture_t *p_src,
845 int i_x_offset, int i_y_offset,
846 int i_width, int i_height, int i_alpha )
848 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
849 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
850 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
851 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
853 bool b_even_scanline = i_y_offset % 2;
855 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
856 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
857 p_filter->fmt_out.video.i_x_offset +
858 p_dst->p[Y_PLANE].i_pitch *
859 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
860 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
861 p_filter->fmt_out.video.i_x_offset/2 +
862 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
863 p_dst->p[U_PLANE].i_pitch;
864 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
865 p_filter->fmt_out.video.i_x_offset/2 +
866 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
867 p_dst->p[V_PLANE].i_pitch;
869 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
870 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
871 p_filter->fmt_out.video.i_x_offset +
872 p_dst_orig->p[Y_PLANE].i_pitch *
873 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
874 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
875 p_filter->fmt_out.video.i_x_offset/2 +
876 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
877 p_dst_orig->p[U_PLANE].i_pitch;
878 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
879 p_filter->fmt_out.video.i_x_offset/2 +
880 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
881 p_dst_orig->p[V_PLANE].i_pitch;
883 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
884 p_src2_y = p_src->p[Y_PLANE].p_pixels +
885 p_filter->fmt_in.video.i_x_offset +
886 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
887 p_src2_u = p_src->p[U_PLANE].p_pixels +
888 p_filter->fmt_in.video.i_x_offset/2 +
889 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
890 p_src2_v = p_src->p[V_PLANE].p_pixels +
891 p_filter->fmt_in.video.i_x_offset/2 +
892 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
894 /* Draw until we reach the bottom of the subtitle */
895 for( i_y = 0; i_y < i_height; i_y++,
896 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
897 p_src2_y += i_src2_pitch )
899 if( b_even_scanline )
901 p_dst_u += i_dst_pitch/2;
902 p_dst_v += i_dst_pitch/2;
903 p_src1_u += i_src1_pitch/2;
904 p_src1_v += i_src1_pitch/2;
906 b_even_scanline = !b_even_scanline;
908 /* Draw until we reach the end of the line */
909 for( i_x = 0; i_x < i_width; i_x++ )
915 p_dst_y[i_x] = vlc_blend( p_src2_y[i_x], p_src1_y[i_x], i_alpha );
916 if( b_even_scanline && i_x % 2 == 0 )
918 p_dst_u[i_x/2] = vlc_blend( p_src2_u[i_x/2], p_src1_u[i_x/2], i_alpha );
919 p_dst_v[i_x/2] = vlc_blend( p_src2_v[i_x/2], p_src1_v[i_x/2], i_alpha );
924 p_src2_u += i_src2_pitch/2;
925 p_src2_v += i_src2_pitch/2;
929 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
930 picture_t *p_dst_orig, picture_t *p_src,
931 int i_x_offset, int i_y_offset,
932 int i_width, int i_height )
934 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
935 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
936 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
937 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
939 bool b_even_scanline = i_y_offset % 2;
941 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
942 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
943 p_filter->fmt_out.video.i_x_offset +
944 p_dst->p[Y_PLANE].i_pitch *
945 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
946 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
947 p_filter->fmt_out.video.i_x_offset/2 +
948 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
949 p_dst->p[U_PLANE].i_pitch;
950 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
951 p_filter->fmt_out.video.i_x_offset/2 +
952 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
953 p_dst->p[V_PLANE].i_pitch;
955 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
956 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
957 p_filter->fmt_out.video.i_x_offset +
958 p_dst_orig->p[Y_PLANE].i_pitch *
959 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
960 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
961 p_filter->fmt_out.video.i_x_offset/2 +
962 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
963 p_dst_orig->p[U_PLANE].i_pitch;
964 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
965 p_filter->fmt_out.video.i_x_offset/2 +
966 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
967 p_dst_orig->p[V_PLANE].i_pitch;
969 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
970 p_src2_y = p_src->p[Y_PLANE].p_pixels +
971 p_filter->fmt_in.video.i_x_offset +
972 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
973 p_src2_u = p_src->p[U_PLANE].p_pixels +
974 p_filter->fmt_in.video.i_x_offset/2 +
975 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
976 p_src2_v = p_src->p[V_PLANE].p_pixels +
977 p_filter->fmt_in.video.i_x_offset/2 +
978 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
982 /* Draw until we reach the bottom of the subtitle */
983 for( i_y = 0; i_y < i_height; i_y++,
984 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
985 p_src2_y += i_src2_pitch )
987 /* Completely opaque. Completely overwrite underlying pixel */
988 vlc_memcpy( p_dst_y, p_src2_y, i_width );
989 if( b_even_scanline )
991 p_dst_u += i_dst_pitch/2;
992 p_dst_v += i_dst_pitch/2;
993 p_src1_u += i_src1_pitch/2;
994 p_src1_v += i_src1_pitch/2;
998 vlc_memcpy( p_dst_u, p_src2_u, i_width/2 );
999 vlc_memcpy( p_dst_v, p_src2_v, i_width/2 );
1001 b_even_scanline = !b_even_scanline;
1004 p_src2_u += i_src2_pitch/2;
1005 p_src2_v += i_src2_pitch/2;
1012 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1013 picture_t *p_dst_orig, picture_t *p_src,
1014 int i_x_offset, int i_y_offset,
1015 int i_width, int i_height, int i_alpha )
1017 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1018 uint8_t *p_dst, *p_src1, *p_src2_y;
1019 uint8_t *p_src2_u, *p_src2_v;
1020 int i_x, i_y, i_pix_pitch;
1023 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1024 i_dst_pitch = p_dst_pic->p->i_pitch;
1025 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1026 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1027 p_dst_pic->p->i_pitch *
1028 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1030 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1031 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1032 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1033 p_dst_orig->p->i_pitch *
1034 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1036 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1037 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1038 p_filter->fmt_in.video.i_x_offset +
1039 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1040 p_src2_u = p_src->p[U_PLANE].p_pixels +
1041 p_filter->fmt_in.video.i_x_offset/2 +
1042 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1043 p_src2_v = p_src->p[V_PLANE].p_pixels +
1044 p_filter->fmt_in.video.i_x_offset/2 +
1045 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1047 /* Draw until we reach the bottom of the subtitle */
1048 for( i_y = 0; i_y < i_height; i_y++,
1049 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1050 p_src2_y += i_src2_pitch )
1052 /* Draw until we reach the end of the line */
1053 for( i_x = 0; i_x < i_width; i_x++ )
1055 if( i_alpha == MAX_TRANS )
1057 /* Completely opaque. Completely overwrite underlying pixel */
1058 yuv_to_rgb( &r, &g, &b,
1059 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1061 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1066 /* FIXME: do the blending
1067 * FIXME use rgb shifts */
1068 yuv_to_rgb( &r, &g, &b,
1069 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1071 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1075 p_src2_u += i_src2_pitch/2;
1076 p_src2_v += i_src2_pitch/2;
1081 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1082 picture_t *p_dst_orig, picture_t *p_src,
1083 int i_x_offset, int i_y_offset,
1084 int i_width, int i_height, int i_alpha )
1086 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1087 uint8_t *p_dst, *p_src1, *p_src2_y;
1088 uint8_t *p_src2_u, *p_src2_v;
1089 int i_x, i_y, i_pix_pitch;
1092 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1093 i_dst_pitch = p_dst_pic->p->i_pitch;
1094 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1095 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1096 p_dst_pic->p->i_pitch *
1097 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1099 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1100 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1101 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1102 p_dst_orig->p->i_pitch *
1103 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1105 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1106 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1107 p_filter->fmt_in.video.i_x_offset +
1108 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1109 p_src2_u = p_src->p[U_PLANE].p_pixels +
1110 p_filter->fmt_in.video.i_x_offset/2 +
1111 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1112 p_src2_v = p_src->p[V_PLANE].p_pixels +
1113 p_filter->fmt_in.video.i_x_offset/2 +
1114 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1116 /* Draw until we reach the bottom of the subtitle */
1117 for( i_y = 0; i_y < i_height; i_y++,
1118 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1119 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1120 p_src2_v += i_src2_pitch )
1122 /* Draw until we reach the end of the line */
1123 for( i_x = 0; i_x < i_width; i_x++ )
1129 yuv_to_rgb( &r, &g, &b,
1130 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1132 p_dst[i_x * i_pix_pitch + 0] = vlc_blend( r, p_src1[i_x * i_pix_pitch + 0], i_alpha );
1133 p_dst[i_x * i_pix_pitch + 1] = vlc_blend( g, p_src1[i_x * i_pix_pitch + 1], i_alpha );
1134 p_dst[i_x * i_pix_pitch + 2] = vlc_blend( b, p_src1[i_x * i_pix_pitch + 2], i_alpha );
1138 p_src2_u += i_src2_pitch/2;
1139 p_src2_v += i_src2_pitch/2;
1144 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1145 picture_t *p_dst_orig, picture_t *p_src,
1146 int i_x_offset, int i_y_offset,
1147 int i_width, int i_height, int i_alpha )
1149 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1150 uint8_t *p_dst, *p_src1, *p_src2_y;
1151 uint8_t *p_src2_u, *p_src2_v;
1152 int i_x, i_y, i_pix_pitch;
1153 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1154 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1156 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1162 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1168 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1176 i_dst_pitch = p_dst_pic->p->i_pitch;
1177 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1178 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1179 p_dst_pic->p->i_pitch *
1180 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1182 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1183 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1184 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1185 p_dst_orig->p->i_pitch *
1186 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1188 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1189 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1190 p_filter->fmt_in.video.i_x_offset +
1191 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1192 p_src2_u = p_src->p[U_PLANE].p_pixels +
1193 p_filter->fmt_in.video.i_x_offset/2 +
1194 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1195 p_src2_v = p_src->p[V_PLANE].p_pixels +
1196 p_filter->fmt_in.video.i_x_offset/2 +
1197 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1199 i_width &= ~1; /* Needs to be a multiple of 2 */
1201 /* Draw until we reach the bottom of the subtitle */
1202 for( i_y = 0; i_y < i_height; i_y++,
1203 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1204 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1205 p_src2_v += i_src2_pitch )
1207 /* Draw until we reach the end of the line */
1208 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1214 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_alpha );
1217 uint16_t i_u = p_src2_u[i_x/2];
1218 uint16_t i_v = p_src2_v[i_x/2];
1219 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_alpha );
1220 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_alpha );
1225 p_src2_u += i_src2_pitch/2;
1226 p_src2_v += i_src2_pitch/2;
1231 /***********************************************************************
1233 ***********************************************************************/
1234 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1235 picture_t *p_dst_orig, picture_t *p_src,
1236 int i_x_offset, int i_y_offset,
1237 int i_width, int i_height, int i_alpha )
1239 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1240 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1241 uint8_t *p_src1_u, *p_dst_u;
1242 uint8_t *p_src1_v, *p_dst_v;
1243 int i_x, i_y, i_trans;
1244 bool b_even_scanline = i_y_offset % 2;
1246 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1247 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1248 p_filter->fmt_out.video.i_x_offset +
1249 p_dst->p[Y_PLANE].i_pitch *
1250 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1251 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1252 p_filter->fmt_out.video.i_x_offset/2 +
1253 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1254 p_dst->p[U_PLANE].i_pitch;
1255 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1256 p_filter->fmt_out.video.i_x_offset/2 +
1257 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1258 p_dst->p[V_PLANE].i_pitch;
1260 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1261 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1262 p_filter->fmt_out.video.i_x_offset +
1263 p_dst_orig->p[Y_PLANE].i_pitch *
1264 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1265 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1266 p_filter->fmt_out.video.i_x_offset/2 +
1267 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1268 p_dst_orig->p[U_PLANE].i_pitch;
1269 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1270 p_filter->fmt_out.video.i_x_offset/2 +
1271 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1272 p_dst_orig->p[V_PLANE].i_pitch;
1274 i_src2_pitch = p_src->p->i_pitch;
1275 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1276 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1278 const uint8_t *p_trans = p_src2;
1279 #define p_pal p_filter->fmt_in.video.p_palette->palette
1281 /* Draw until we reach the bottom of the subtitle */
1282 for( i_y = 0; i_y < i_height; i_y++,
1283 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1284 p_src2 += i_src2_pitch,
1285 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1286 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1287 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1288 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1290 b_even_scanline = !b_even_scanline;
1292 /* Draw until we reach the end of the line */
1293 for( i_x = 0; i_x < i_width; i_x++ )
1295 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1300 p_dst_y[i_x] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1_y[i_x], i_trans );
1301 if( b_even_scanline && ((i_x % 2) == 0) )
1303 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src2[i_x]][1], p_src1_u[i_x/2], i_trans );
1304 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src2[i_x]][2], p_src1_v[i_x/2], i_trans );
1311 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1312 picture_t *p_dst_orig, picture_t *p_src,
1313 int i_x_offset, int i_y_offset,
1314 int i_width, int i_height, int i_alpha )
1316 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1317 uint8_t *p_src1, *p_src2, *p_dst;
1318 int i_x, i_y, i_pix_pitch, i_trans;
1319 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1320 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1322 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1328 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1334 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1342 i_dst_pitch = p_dst_pic->p->i_pitch;
1343 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1344 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1345 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1347 i_src1_pitch = p_dst_orig->p->i_pitch;
1348 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1349 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1350 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1352 i_src2_pitch = p_src->p->i_pitch;
1353 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1354 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1356 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1358 const uint8_t *p_trans = p_src2;
1359 #define p_pal p_filter->fmt_in.video.p_palette->palette
1361 /* Draw until we reach the bottom of the subtitle */
1362 for( i_y = 0; i_y < i_height; i_y++,
1363 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1365 /* Draw until we reach the end of the line */
1366 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1368 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1373 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1[i_x * 2 + i_l_offset], i_trans );
1378 if( p_trans[i_x+1] > 0xaa )
1380 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1381 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1385 i_u = p_pal[p_src2[i_x]][1];
1386 i_v = p_pal[p_src2[i_x]][2];
1389 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_trans );
1390 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_trans );
1397 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1398 picture_t *p_dst_orig, picture_t *p_src,
1399 int i_x_offset, int i_y_offset,
1400 int i_width, int i_height, int i_alpha )
1402 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1403 uint8_t *p_src1, *p_src2, *p_dst;
1404 int i_x, i_y, i_pix_pitch, i_trans;
1406 video_palette_t rgbpalette;
1408 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1409 i_dst_pitch = p_dst_pic->p->i_pitch;
1410 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1411 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1412 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1414 i_src1_pitch = p_dst_orig->p->i_pitch;
1415 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1416 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1417 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1419 i_src2_pitch = p_src->p->i_pitch;
1420 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1421 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1423 const uint8_t *p_trans = p_src2;
1424 #define p_pal p_filter->fmt_in.video.p_palette->palette
1425 #define rgbpal rgbpalette.palette
1427 /* Convert palette first */
1428 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1431 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1433 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1435 *(uint16_t *)rgbpal[i_y] =
1436 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1440 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1444 /* Draw until we reach the bottom of the subtitle */
1445 for( i_y = 0; i_y < i_height; i_y++,
1446 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1448 /* Draw until we reach the end of the line */
1449 for( i_x = 0; i_x < i_width; i_x++ )
1451 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1455 if( i_trans == MAX_TRANS ||
1456 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1458 /* FIXME implement blending for RV16 */
1459 /* Completely opaque. Completely overwrite underlying pixel */
1460 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1461 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1462 if( p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','1','6') )
1463 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1468 p_dst[i_x * i_pix_pitch + 0] = vlc_blend( rgbpal[p_src2[i_x]][0], p_src1[i_x * i_pix_pitch + 0], i_trans );
1469 p_dst[i_x * i_pix_pitch + 1] = vlc_blend( rgbpal[p_src2[i_x]][1], p_src1[i_x * i_pix_pitch + 1], i_trans );
1470 p_dst[i_x * i_pix_pitch + 2] = vlc_blend( rgbpal[p_src2[i_x]][2], p_src1[i_x * i_pix_pitch + 2], i_trans );
1478 /***********************************************************************
1480 ***********************************************************************/
1481 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1482 picture_t *p_dst_orig, picture_t *p_src,
1483 int i_x_offset, int i_y_offset,
1484 int i_width, int i_height, int i_alpha )
1486 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1487 uint8_t *p_src1_y, *p_dst_y;
1488 uint8_t *p_src1_u, *p_dst_u;
1489 uint8_t *p_src1_v, *p_dst_v;
1491 int i_x, i_y, i_trans;
1494 bool b_even_scanline = i_y_offset % 2;
1496 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1497 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1498 p_filter->fmt_out.video.i_x_offset +
1499 p_dst->p[Y_PLANE].i_pitch *
1500 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1501 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1502 p_filter->fmt_out.video.i_x_offset/2 +
1503 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1504 p_dst->p[U_PLANE].i_pitch;
1505 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1506 p_filter->fmt_out.video.i_x_offset/2 +
1507 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1508 p_dst->p[V_PLANE].i_pitch;
1510 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1511 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1512 p_filter->fmt_out.video.i_x_offset +
1513 p_dst_orig->p[Y_PLANE].i_pitch *
1514 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1515 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1516 p_filter->fmt_out.video.i_x_offset/2 +
1517 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1518 p_dst_orig->p[U_PLANE].i_pitch;
1519 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1520 p_filter->fmt_out.video.i_x_offset/2 +
1521 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1522 p_dst_orig->p[V_PLANE].i_pitch;
1524 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1525 i_src2_pitch = p_src->p->i_pitch;
1526 p_src2 = p_src->p->p_pixels +
1527 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1528 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1531 /* Draw until we reach the bottom of the subtitle */
1532 for( i_y = 0; i_y < i_height; i_y++,
1533 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1534 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1535 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1536 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1537 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1538 p_src2 += i_src2_pitch )
1540 b_even_scanline = !b_even_scanline;
1542 /* Draw until we reach the end of the line */
1543 for( i_x = 0; i_x < i_width; i_x++ )
1545 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1546 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1547 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1548 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1553 rgb_to_yuv( &y, &u, &v, R, G, B );
1555 p_dst_y[i_x] = vlc_blend( y, p_src1_y[i_x], i_trans );
1556 if( b_even_scanline && i_x % 2 == 0 )
1558 p_dst_u[i_x/2] = vlc_blend( u, p_src1_u[i_x/2], i_trans );
1559 p_dst_v[i_x/2] = vlc_blend( v, p_src1_v[i_x/2], i_trans );
1568 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1569 picture_t *p_dst_orig, picture_t *p_src,
1570 int i_x_offset, int i_y_offset,
1571 int i_width, int i_height, int i_alpha )
1573 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1574 uint8_t *p_dst, *p_src1, *p_src2;
1575 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1577 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1578 i_dst_pitch = p_dst_pic->p->i_pitch;
1579 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1580 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1581 p_dst_pic->p->i_pitch *
1582 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1584 i_src1_pitch = p_dst_orig->p->i_pitch;
1585 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1586 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1587 p_dst_orig->p->i_pitch *
1588 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1590 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1591 i_src2_pitch = p_src->p->i_pitch;
1592 p_src2 = p_src->p->p_pixels +
1593 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1594 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1596 /* Draw until we reach the bottom of the subtitle */
1597 for( i_y = 0; i_y < i_height; i_y++,
1598 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1600 /* Draw until we reach the end of the line */
1601 for( i_x = 0; i_x < i_width; i_x++ )
1603 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1604 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1605 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1606 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1611 p_dst[i_x * i_pix_pitch + 0] = vlc_blend( R, p_src1[i_x * i_pix_pitch + 0], i_trans );
1612 p_dst[i_x * i_pix_pitch + 1] = vlc_blend( G, p_src1[i_x * i_pix_pitch + 1], i_trans );
1613 p_dst[i_x * i_pix_pitch + 2] = vlc_blend( B, p_src1[i_x * i_pix_pitch + 2], i_trans );
1621 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1622 picture_t *p_dst_orig, picture_t *p_src,
1623 int i_x_offset, int i_y_offset,
1624 int i_width, int i_height, int i_alpha )
1626 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1627 uint8_t *p_dst, *p_src1, *p_src2;
1628 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1631 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1632 i_dst_pitch = p_dst_pic->p->i_pitch;
1633 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1634 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1635 p_dst_pic->p->i_pitch *
1636 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1638 i_src1_pitch = p_dst_orig->p->i_pitch;
1639 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1640 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1641 p_dst_orig->p->i_pitch *
1642 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1644 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1645 i_src2_pitch = p_src->p->i_pitch;
1646 p_src2 = p_src->p->p_pixels +
1647 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1648 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1650 /* Draw until we reach the bottom of the subtitle */
1651 for( i_y = 0; i_y < i_height; i_y++,
1652 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1654 /* Draw until we reach the end of the line */
1655 for( i_x = 0; i_x < i_width; i_x++ )
1657 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1658 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1659 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1660 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1664 else if( i_trans == MAX_TRANS )
1666 /* Completely opaque. Completely overwrite underlying pixel */
1667 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1672 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1673 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1674 ( vlc_blend( R >> 3, ((i_pix )>> 11), i_trans ) << 11 ) |
1675 ( vlc_blend( G >> 2, ((i_pix & 0x07e0)>> 5), i_trans ) << 5 ) |
1676 ( vlc_blend( B >> 3, ((i_pix & 0x001f) ), i_trans ) );
1684 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1685 picture_t *p_dst_orig, picture_t *p_src,
1686 int i_x_offset, int i_y_offset,
1687 int i_width, int i_height, int i_alpha )
1689 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1690 uint8_t *p_dst, *p_src1, *p_src2;
1692 int i_x, i_y, i_pix_pitch, i_trans;
1693 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1694 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1697 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1703 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1709 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1717 i_dst_pitch = p_dst_pic->p->i_pitch;
1718 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1719 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1720 p_dst_pic->p->i_pitch *
1721 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1723 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1724 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1725 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1726 p_dst_orig->p->i_pitch *
1727 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1729 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1730 i_src2_pitch = p_src->p->i_pitch;
1731 p_src2 = p_src->p->p_pixels +
1732 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1733 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1735 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1737 /* Draw until we reach the bottom of the subtitle */
1738 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
1739 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1740 p_src2 += i_src2_pitch )
1742 /* Draw until we reach the end of the line */
1743 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1745 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1746 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1747 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1748 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1753 rgb_to_yuv( &y, &u, &v, R, G, B );
1754 p_dst[i_x * 2 + i_l_offset] = vlc_blend( y, p_src1[i_x * 2 + i_l_offset], i_trans );
1757 p_dst[i_x * 2 + i_u_offset] = vlc_blend( u, p_src1[i_x * 2 + i_u_offset], i_trans );
1758 p_dst[i_x * 2 + i_v_offset] = vlc_blend( v, p_src1[i_x * 2 + i_v_offset], i_trans );