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 *****************************************************************************/
34 #include "vlc_filter.h"
36 /*****************************************************************************
37 * filter_sys_t : filter descriptor
38 *****************************************************************************/
44 /****************************************************************************
46 ****************************************************************************/
47 static int OpenFilter ( vlc_object_t * );
48 static void CloseFilter( vlc_object_t * );
50 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
53 /* TODO i_alpha support for BlendR16 */
55 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
56 int, int, int, int, int );
57 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
58 int, int, int, int, int );
59 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
60 int, int, int, int, int );
61 static void BlendYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
62 int, int, int, int, int );
65 static void BlendI420I420( filter_t *, picture_t *, picture_t *, picture_t *,
66 int, int, int, int, int );
67 static void BlendI420I420_no_alpha(
68 filter_t *, picture_t *, picture_t *, picture_t *,
70 static void BlendI420R16( filter_t *, picture_t *, picture_t *, picture_t *,
71 int, int, int, int, int );
72 static void BlendI420R24( filter_t *, picture_t *, picture_t *, picture_t *,
73 int, int, int, int, int );
74 static void BlendI420YUVPacked( filter_t *, picture_t *, picture_t *,
75 picture_t *, int, int, int, int, int );
78 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
79 int, int, int, int, int );
80 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
81 int, int, int, int, int );
82 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
83 int, int, int, int, int );
86 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
87 int, int, int, int, int );
88 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
89 picture_t *, int, int, int, int, int );
90 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
91 int, int, int, int, int );
92 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
93 int, int, int, int, int );
95 /*****************************************************************************
97 *****************************************************************************/
99 set_description( _("Video pictures blending") );
100 set_capability( "video blending", 100 );
101 set_callbacks( OpenFilter, CloseFilter );
104 /*****************************************************************************
105 * OpenFilter: probe the filter and return score
106 *****************************************************************************/
107 static int OpenFilter( vlc_object_t *p_this )
109 filter_t *p_filter = (filter_t*)p_this;
112 /* Check if we can handle that format.
113 * We could try to use a chroma filter if we can't. */
114 int in_chroma = p_filter->fmt_in.video.i_chroma;
115 int out_chroma = p_filter->fmt_out.video.i_chroma;
116 if( ( in_chroma != VLC_FOURCC('Y','U','V','A') &&
117 in_chroma != VLC_FOURCC('I','4','2','0') &&
118 in_chroma != VLC_FOURCC('Y','V','1','2') &&
119 in_chroma != VLC_FOURCC('Y','U','V','P') &&
120 in_chroma != VLC_FOURCC('R','G','B','A') ) ||
121 ( out_chroma != VLC_FOURCC('I','4','2','0') &&
122 out_chroma != VLC_FOURCC('Y','U','Y','2') &&
123 out_chroma != VLC_FOURCC('Y','V','1','2') &&
124 out_chroma != VLC_FOURCC('U','Y','V','Y') &&
125 out_chroma != VLC_FOURCC('Y','V','Y','U') &&
126 out_chroma != VLC_FOURCC('R','V','1','6') &&
127 out_chroma != VLC_FOURCC('R','V','2','4') &&
128 out_chroma != VLC_FOURCC('R','V','3','2') ) )
133 /* Allocate the memory needed to store the decoder's structure */
134 if( ( p_filter->p_sys = p_sys =
135 (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
137 msg_Err( p_filter, "out of memory" );
142 p_filter->pf_video_blend = Blend;
144 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
145 (char *)&p_filter->fmt_in.video.i_chroma,
146 (char *)&p_filter->fmt_out.video.i_chroma );
151 /*****************************************************************************
152 * CloseFilter: clean up the filter
153 *****************************************************************************/
154 static void CloseFilter( vlc_object_t *p_this )
156 filter_t *p_filter = (filter_t*)p_this;
157 filter_sys_t *p_sys = p_filter->p_sys;
162 /****************************************************************************
163 * Blend: the whole thing
164 ****************************************************************************
165 * This function is called just after the thread is launched.
166 ****************************************************************************/
167 static void Blend( filter_t *p_filter, picture_t *p_dst,
168 picture_t *p_dst_orig, picture_t *p_src,
169 int i_x_offset, int i_y_offset, int i_alpha )
171 int i_width, i_height;
173 if( i_alpha == 0 ) return;
175 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
176 (int)p_filter->fmt_in.video.i_visible_width);
178 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
179 (int)p_filter->fmt_in.video.i_visible_height);
181 if( i_width <= 0 || i_height <= 0 ) return;
184 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
185 (char *)&p_filter->fmt_in.video.i_chroma,
186 (char *)&p_filter->fmt_out.video.i_chroma );
189 switch( p_filter->fmt_in.video.i_chroma )
191 case VLC_FOURCC('Y','U','V','A'):
192 switch( p_filter->fmt_out.video.i_chroma )
194 case VLC_FOURCC('I','4','2','0'):
195 case VLC_FOURCC('Y','V','1','2'):
196 BlendI420( p_filter, p_dst, p_dst_orig, p_src,
197 i_x_offset, i_y_offset,
198 i_width, i_height, i_alpha );
200 case VLC_FOURCC('Y','U','Y','2'):
201 case VLC_FOURCC('U','Y','V','Y'):
202 case VLC_FOURCC('Y','V','Y','U'):
203 BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
204 i_x_offset, i_y_offset,
205 i_width, i_height, i_alpha );
207 case VLC_FOURCC('R','V','1','6'):
208 BlendR16( p_filter, p_dst, p_dst_orig, p_src,
209 i_x_offset, i_y_offset,
210 i_width, i_height, i_alpha );
212 case VLC_FOURCC('R','V','2','4'):
213 case VLC_FOURCC('R','V','3','2'):
214 BlendR24( p_filter, p_dst, p_dst_orig, p_src,
215 i_x_offset, i_y_offset,
216 i_width, i_height, i_alpha );
219 case VLC_FOURCC('Y','U','V','P'):
220 switch( p_filter->fmt_out.video.i_chroma )
222 case VLC_FOURCC('I','4','2','0'):
223 case VLC_FOURCC('Y','V','1','2'):
224 BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
225 i_x_offset, i_y_offset,
226 i_width, i_height, i_alpha );
228 case VLC_FOURCC('Y','U','Y','2'):
229 case VLC_FOURCC('U','Y','V','Y'):
230 case VLC_FOURCC('Y','V','Y','U'):
231 BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
232 i_x_offset, i_y_offset,
233 i_width, i_height, i_alpha );
235 case VLC_FOURCC('R','V','1','6'):
236 case VLC_FOURCC('R','V','2','4'):
237 case VLC_FOURCC('R','V','3','2'):
238 BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
239 i_x_offset, i_y_offset,
240 i_width, i_height, i_alpha );
243 case VLC_FOURCC('Y','V','1','2'):
244 case VLC_FOURCC('I','4','2','0'):
245 switch( p_filter->fmt_out.video.i_chroma )
247 case VLC_FOURCC('I','4','2','0'):
248 case VLC_FOURCC('Y','V','1','2'):
249 if( i_alpha == 0xff )
250 BlendI420I420_no_alpha(
251 p_filter, p_dst, p_dst_orig, p_src,
252 i_x_offset, i_y_offset,
255 BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
256 i_x_offset, i_y_offset,
257 i_width, i_height, i_alpha );
259 case VLC_FOURCC('Y','U','Y','2'):
260 case VLC_FOURCC('U','Y','V','Y'):
261 case VLC_FOURCC('Y','V','Y','U'):
262 BlendI420YUVPacked( p_filter, p_dst, p_dst_orig, p_src,
263 i_x_offset, i_y_offset,
264 i_width, i_height, i_alpha );
266 case VLC_FOURCC('R','V','1','6'):
267 BlendI420R16( p_filter, p_dst, p_dst_orig, p_src,
268 i_x_offset, i_y_offset,
269 i_width, i_height, i_alpha );
271 case VLC_FOURCC('R','V','2','4'):
272 case VLC_FOURCC('R','V','3','2'):
273 BlendI420R24( p_filter, p_dst, p_dst_orig, p_src,
274 i_x_offset, i_y_offset,
275 i_width, i_height, i_alpha );
278 case VLC_FOURCC('R','G','B','A'):
279 switch( p_filter->fmt_out.video.i_chroma )
281 case VLC_FOURCC('I','4','2','0'):
282 case VLC_FOURCC('Y','V','1','2'):
283 BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
284 i_x_offset, i_y_offset,
285 i_width, i_height, i_alpha );
287 case VLC_FOURCC('Y','U','Y','2'):
288 case VLC_FOURCC('U','Y','V','Y'):
289 case VLC_FOURCC('Y','V','Y','U'):
290 BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
291 i_x_offset, i_y_offset,
292 i_width, i_height, i_alpha );
294 case VLC_FOURCC('R','V','2','4'):
295 case VLC_FOURCC('R','V','3','2'):
296 BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
297 i_x_offset, i_y_offset,
298 i_width, i_height, i_alpha );
300 case VLC_FOURCC('R','V','1','6'):
301 BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
302 i_x_offset, i_y_offset,
303 i_width, i_height, i_alpha );
308 msg_Dbg( p_filter, "no matching alpha blending routine "
309 "(chroma: %4.4s -> %4.4s)",
310 (char *)&p_filter->fmt_in.video.i_chroma,
311 (char *)&p_filter->fmt_out.video.i_chroma );
314 /***********************************************************************
316 ***********************************************************************/
317 static inline void yuv_to_rgb( int *r, int *g, int *b,
318 uint8_t y1, uint8_t u1, uint8_t v1 )
320 /* macros used for YUV pixel conversions */
321 # define SCALEBITS 10
322 # define ONE_HALF (1 << (SCALEBITS - 1))
323 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
324 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
326 int y, cb, cr, r_add, g_add, b_add;
330 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
331 g_add = - FIX(0.34414*255.0/224.0) * cb
332 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
333 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
334 y = (y1 - 16) * FIX(255.0/219.0);
335 *r = CLAMP((y + r_add) >> SCALEBITS);
336 *g = CLAMP((y + g_add) >> SCALEBITS);
337 *b = CLAMP((y + b_add) >> SCALEBITS);
340 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
341 int r, int g, int b )
343 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
344 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
345 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
348 /***********************************************************************
350 ***********************************************************************/
351 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
352 picture_t *p_dst_orig, picture_t *p_src,
353 int i_x_offset, int i_y_offset,
354 int i_width, int i_height, int i_alpha )
356 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
357 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
358 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
359 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
361 int i_x, i_y, i_trans = 0;
362 vlc_bool_t b_even_scanline = i_y_offset % 2;
364 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
365 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
366 p_filter->fmt_out.video.i_x_offset +
367 p_dst->p[Y_PLANE].i_pitch *
368 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
369 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
370 p_filter->fmt_out.video.i_x_offset/2 +
371 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
372 p_dst->p[U_PLANE].i_pitch;
373 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
374 p_filter->fmt_out.video.i_x_offset/2 +
375 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
376 p_dst->p[V_PLANE].i_pitch;
378 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
379 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
380 p_filter->fmt_out.video.i_x_offset +
381 p_dst_orig->p[Y_PLANE].i_pitch *
382 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
383 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
384 p_filter->fmt_out.video.i_x_offset/2 +
385 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
386 p_dst_orig->p[U_PLANE].i_pitch;
387 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
388 p_filter->fmt_out.video.i_x_offset/2 +
389 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
390 p_dst_orig->p[V_PLANE].i_pitch;
392 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
393 p_src2_y = p_src->p[Y_PLANE].p_pixels +
394 p_filter->fmt_in.video.i_x_offset +
395 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
396 p_src2_u = p_src->p[U_PLANE].p_pixels +
397 p_filter->fmt_in.video.i_x_offset/2 +
398 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
399 p_src2_v = p_src->p[V_PLANE].p_pixels +
400 p_filter->fmt_in.video.i_x_offset/2 +
401 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
403 p_trans = p_src->p[A_PLANE].p_pixels +
404 p_filter->fmt_in.video.i_x_offset +
405 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
407 #define MAX_TRANS 255
410 /* Draw until we reach the bottom of the subtitle */
411 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
412 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
413 p_src2_y += i_src2_pitch,
414 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
415 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
416 p_src2_u += i_src2_pitch,
417 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
418 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
419 p_src2_v += i_src2_pitch )
421 b_even_scanline = !b_even_scanline;
423 /* Draw until we reach the end of the line */
424 for( i_x = 0; i_x < i_width; i_x++ )
427 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
430 /* Completely transparent. Don't change pixel */
433 else if( i_trans == MAX_TRANS )
435 /* Completely opaque. Completely overwrite underlying pixel */
436 p_dst_y[i_x] = p_src2_y[i_x];
438 if( b_even_scanline && i_x % 2 == 0 )
440 p_dst_u[i_x/2] = p_src2_u[i_x];
441 p_dst_v[i_x/2] = p_src2_v[i_x];
447 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
448 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
451 if( b_even_scanline && i_x % 2 == 0 )
453 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
454 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
456 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
457 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
469 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
470 picture_t *p_dst_orig, picture_t *p_src,
471 int i_x_offset, int i_y_offset,
472 int i_width, int i_height, int i_alpha )
474 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
475 uint8_t *p_dst, *p_src1, *p_src2_y;
476 uint8_t *p_src2_u, *p_src2_v;
478 int i_x, i_y, i_pix_pitch, i_trans = 0;
481 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
482 i_dst_pitch = p_dst_pic->p->i_pitch;
483 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
484 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
485 p_dst_pic->p->i_pitch *
486 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
488 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
489 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
490 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
491 p_dst_orig->p->i_pitch *
492 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
494 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
495 p_src2_y = p_src->p[Y_PLANE].p_pixels +
496 p_filter->fmt_in.video.i_x_offset +
497 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
498 p_src2_u = p_src->p[U_PLANE].p_pixels +
499 p_filter->fmt_in.video.i_x_offset/2 +
500 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
501 p_src2_v = p_src->p[V_PLANE].p_pixels +
502 p_filter->fmt_in.video.i_x_offset/2 +
503 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
505 p_trans = p_src->p[A_PLANE].p_pixels +
506 p_filter->fmt_in.video.i_x_offset +
507 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
509 #define MAX_TRANS 255
512 /* Draw until we reach the bottom of the subtitle */
513 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
514 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
515 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
516 p_src2_v += i_src2_pitch )
518 /* Draw until we reach the end of the line */
519 for( i_x = 0; i_x < i_width; i_x++ )
522 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
525 /* Completely transparent. Don't change pixel */
528 else if( i_trans == MAX_TRANS )
530 /* Completely opaque. Completely overwrite underlying pixel */
531 yuv_to_rgb( &r, &g, &b,
532 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
534 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
539 /* FIXME: do the blending */
540 yuv_to_rgb( &r, &g, &b,
541 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
543 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
553 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
554 picture_t *p_dst_orig, picture_t *p_src,
555 int i_x_offset, int i_y_offset,
556 int i_width, int i_height, int i_alpha )
558 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
559 uint8_t *p_dst, *p_src1, *p_src2_y;
560 uint8_t *p_src2_u, *p_src2_v;
562 int i_x, i_y, i_pix_pitch, i_trans = 0;
565 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
566 i_dst_pitch = p_dst_pic->p->i_pitch;
567 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
568 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
569 p_dst_pic->p->i_pitch *
570 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
572 i_src1_pitch = p_dst_orig->p->i_pitch;
573 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
574 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
575 p_dst_orig->p->i_pitch *
576 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
578 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
579 p_src2_y = p_src->p[Y_PLANE].p_pixels +
580 p_filter->fmt_in.video.i_x_offset +
581 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
582 p_src2_u = p_src->p[U_PLANE].p_pixels +
583 p_filter->fmt_in.video.i_x_offset/2 +
584 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
585 p_src2_v = p_src->p[V_PLANE].p_pixels +
586 p_filter->fmt_in.video.i_x_offset/2 +
587 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
589 p_trans = p_src->p[A_PLANE].p_pixels +
590 p_filter->fmt_in.video.i_x_offset +
591 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
593 #define MAX_TRANS 255
596 if( (i_pix_pitch == 4)
597 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
601 ** if picture pixels are 32 bits long and lines addresses are 32 bit
602 ** aligned, optimize rendering
604 uint32_t *p32_dst = (uint32_t *)p_dst;
605 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
606 uint32_t *p32_src1 = (uint32_t *)p_src1;
607 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
609 int i_rshift, i_gshift, i_bshift;
610 uint32_t i_rmask, i_gmask, i_bmask;
612 if( p_dst_pic->p_heap )
614 i_rmask = p_dst_pic->p_heap->i_rmask;
615 i_gmask = p_dst_pic->p_heap->i_gmask;
616 i_bmask = p_dst_pic->p_heap->i_bmask;
617 i_rshift = p_dst_pic->p_heap->i_lrshift;
618 i_gshift = p_dst_pic->p_heap->i_lgshift;
619 i_bshift = p_dst_pic->p_heap->i_lbshift;
623 i_rmask = p_dst_pic->format.i_rmask;
624 i_gmask = p_dst_pic->format.i_gmask;
625 i_bmask = p_dst_pic->format.i_bmask;
627 if( (i_rmask == 0x00FF0000)
628 && (i_gmask == 0x0000FF00)
629 && (i_bmask == 0x000000FF) )
631 /* X8R8G8B8 pixel layout */
636 else if( (i_rmask == 0xFF000000)
637 && (i_gmask == 0x00FF0000)
638 && (i_bmask == 0x0000FF00) )
640 /* R8G8B8X8 pixel layout */
650 /* Draw until we reach the bottom of the subtitle */
651 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
652 p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
653 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
654 p_src2_v += i_src2_pitch )
656 /* Draw until we reach the end of the line */
657 for( i_x = 0; i_x < i_width; i_x++ )
660 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
663 /* Completely transparent. Don't change pixel */
666 else if( i_trans == MAX_TRANS )
668 /* Completely opaque. Completely overwrite underlying pixel */
669 yuv_to_rgb( &r, &g, &b,
670 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
672 p32_dst[i_x] = (r<<i_rshift)
679 uint32_t i_pix_src1 = p32_src1[i_x];
680 yuv_to_rgb( &r, &g, &b,
681 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
683 p32_dst[i_x] = ( ( r * i_trans +
684 (uint16_t)((i_pix_src1 & i_rmask)>>i_rshift) *
685 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_rshift
687 (uint16_t)((i_pix_src1 & i_gmask)>>i_gshift) *
688 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_gshift
690 (uint16_t)((i_pix_src1 & i_bmask)>>i_bshift) *
691 (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_bshift;
698 int i_rindex, i_bindex, i_gindex;
699 uint32_t i_rmask, i_gmask, i_bmask;
703 i_rmask = p_dst_pic->format.i_rmask;
704 i_gmask = p_dst_pic->format.i_gmask;
705 i_bmask = p_dst_pic->format.i_bmask;
708 ** quick and dirty way to get byte index from mask
709 ** will only work correctly if mask are 8 bit aligned
710 ** and are 8 bit long
712 #ifdef WORDS_BIGENDIAN
713 i_rindex = ((i_rmask>>16) & 1)
716 i_gindex = ((i_gmask>>16) & 1)
719 i_bindex = ((i_bmask>>16) & 1)
723 i_rindex = ((i_rmask>>24) & 3)
724 | ((i_rmask>>16) & 2)
725 | ((i_rmask>>8) & 1);
726 i_gindex = ((i_gmask>>24) & 3)
727 | ((i_gmask>>16) & 2)
728 | ((i_gmask>>8) & 1);
729 i_bindex = ((i_bmask>>24) & 3)
730 | ((i_bmask>>16) & 2)
731 | ((i_bmask>>8) & 1);
734 /* Draw until we reach the bottom of the subtitle */
735 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
736 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
737 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
738 p_src2_v += i_src2_pitch )
740 /* Draw until we reach the end of the line */
741 for( i_x = 0; i_x < i_width; i_x++ )
744 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
747 /* Completely transparent. Don't change pixel */
752 int i_pos = i_x * i_pix_pitch;
753 if( i_trans == MAX_TRANS )
756 /* Completely opaque. Completely overwrite underlying pixel */
757 yuv_to_rgb( &r, &g, &b,
758 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
760 p_dst[i_pos + i_rindex ] = r;
761 p_dst[i_pos + i_gindex ] = g;
762 p_dst[i_pos + i_bindex ] = b;
766 int i_rpos = i_pos + i_rindex;
767 int i_gpos = i_pos + i_gindex;
768 int i_bpos = i_pos + i_bindex;
771 yuv_to_rgb( &r, &g, &b,
772 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
774 p_dst[i_rpos] = ( r * i_trans +
775 (uint16_t)p_src1[i_rpos] *
776 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
777 p_dst[i_gpos] = ( r * i_trans +
778 (uint16_t)p_src1[i_gpos] *
779 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
780 p_dst[i_bpos] = ( r * i_trans +
781 (uint16_t)p_src1[i_gpos] *
782 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
795 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
796 picture_t *p_dst_orig, picture_t *p_src,
797 int i_x_offset, int i_y_offset,
798 int i_width, int i_height, int i_alpha )
800 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
801 uint8_t *p_dst, *p_src1, *p_src2_y;
802 uint8_t *p_src2_u, *p_src2_v;
804 int i_x, i_y, i_pix_pitch, i_trans = 0;
805 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
806 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
808 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
814 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
820 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
828 i_dst_pitch = p_dst_pic->p->i_pitch;
829 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
830 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
831 p_dst_pic->p->i_pitch *
832 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
834 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
835 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
836 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
837 p_dst_orig->p->i_pitch *
838 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
840 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
841 p_src2_y = p_src->p[Y_PLANE].p_pixels +
842 p_filter->fmt_in.video.i_x_offset +
843 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
844 p_src2_u = p_src->p[U_PLANE].p_pixels +
845 p_filter->fmt_in.video.i_x_offset/2 +
846 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
847 p_src2_v = p_src->p[V_PLANE].p_pixels +
848 p_filter->fmt_in.video.i_x_offset/2 +
849 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
851 p_trans = p_src->p[A_PLANE].p_pixels +
852 p_filter->fmt_in.video.i_x_offset +
853 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
855 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
857 #define MAX_TRANS 255
860 /* Draw until we reach the bottom of the subtitle */
861 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
862 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
863 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
864 p_src2_v += i_src2_pitch )
866 /* Draw until we reach the end of the line */
867 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
869 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
872 /* Completely transparent. Don't change pixel */
874 else if( i_trans == MAX_TRANS )
876 /* Completely opaque. Completely overwrite underlying pixel */
877 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
881 if( p_trans[i_x+1] > 0xaa )
883 p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
884 p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
888 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
889 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
896 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_trans +
897 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
904 if( p_trans[i_x+1] > 0xaa )
906 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
907 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
914 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
915 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
917 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
918 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
930 /***********************************************************************
932 ***********************************************************************/
933 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
934 picture_t *p_dst_orig, picture_t *p_src,
935 int i_x_offset, int i_y_offset,
936 int i_width, int i_height, int i_alpha )
938 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
939 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
940 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
941 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
943 vlc_bool_t b_even_scanline = i_y_offset % 2;
945 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
946 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
947 p_filter->fmt_out.video.i_x_offset +
948 p_dst->p[Y_PLANE].i_pitch *
949 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
950 p_dst_u = p_dst->p[U_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[U_PLANE].i_pitch;
954 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
955 p_filter->fmt_out.video.i_x_offset/2 +
956 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
957 p_dst->p[V_PLANE].i_pitch;
959 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
960 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
961 p_filter->fmt_out.video.i_x_offset +
962 p_dst_orig->p[Y_PLANE].i_pitch *
963 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
964 p_src1_u = p_dst_orig->p[U_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[U_PLANE].i_pitch;
968 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
969 p_filter->fmt_out.video.i_x_offset/2 +
970 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
971 p_dst_orig->p[V_PLANE].i_pitch;
973 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
974 p_src2_y = p_src->p[Y_PLANE].p_pixels +
975 p_filter->fmt_in.video.i_x_offset +
976 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
977 p_src2_u = p_src->p[U_PLANE].p_pixels +
978 p_filter->fmt_in.video.i_x_offset/2 +
979 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
980 p_src2_v = p_src->p[V_PLANE].p_pixels +
981 p_filter->fmt_in.video.i_x_offset/2 +
982 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
984 #define MAX_TRANS 255
987 /* Draw until we reach the bottom of the subtitle */
988 for( i_y = 0; i_y < i_height; i_y++,
989 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
990 p_src2_y += i_src2_pitch )
992 if( b_even_scanline )
994 p_dst_u += i_dst_pitch/2;
995 p_dst_v += i_dst_pitch/2;
996 p_src1_u += i_src1_pitch/2;
997 p_src1_v += i_src1_pitch/2;
999 b_even_scanline = !b_even_scanline;
1001 /* Draw until we reach the end of the line */
1002 for( i_x = 0; i_x < i_width; i_x++ )
1004 if( i_alpha == MAX_TRANS )
1006 /* Completely opaque. Completely overwrite underlying pixel */
1007 p_dst_y[i_x] = p_src2_y[i_x];
1009 if( b_even_scanline && i_x % 2 == 0 )
1011 p_dst_u[i_x/2] = p_src2_u[i_x/2];
1012 p_dst_v[i_x/2] = p_src2_v[i_x/2];
1018 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1019 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_alpha) )
1022 if( b_even_scanline && i_x % 2 == 0 )
1024 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x/2] * i_alpha +
1025 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_alpha) )
1027 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x/2] * i_alpha +
1028 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_alpha) )
1034 p_src2_u += i_src2_pitch/2;
1035 p_src2_v += i_src2_pitch/2;
1044 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
1045 picture_t *p_dst_orig, picture_t *p_src,
1046 int i_x_offset, int i_y_offset,
1047 int i_width, int i_height )
1049 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1050 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
1051 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
1052 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
1054 vlc_bool_t b_even_scanline = i_y_offset % 2;
1056 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1057 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1058 p_filter->fmt_out.video.i_x_offset +
1059 p_dst->p[Y_PLANE].i_pitch *
1060 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1061 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1062 p_filter->fmt_out.video.i_x_offset/2 +
1063 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1064 p_dst->p[U_PLANE].i_pitch;
1065 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1066 p_filter->fmt_out.video.i_x_offset/2 +
1067 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1068 p_dst->p[V_PLANE].i_pitch;
1070 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1071 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1072 p_filter->fmt_out.video.i_x_offset +
1073 p_dst_orig->p[Y_PLANE].i_pitch *
1074 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1075 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1076 p_filter->fmt_out.video.i_x_offset/2 +
1077 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1078 p_dst_orig->p[U_PLANE].i_pitch;
1079 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1080 p_filter->fmt_out.video.i_x_offset/2 +
1081 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1082 p_dst_orig->p[V_PLANE].i_pitch;
1084 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1085 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1086 p_filter->fmt_in.video.i_x_offset +
1087 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1088 p_src2_u = p_src->p[U_PLANE].p_pixels +
1089 p_filter->fmt_in.video.i_x_offset/2 +
1090 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1091 p_src2_v = p_src->p[V_PLANE].p_pixels +
1092 p_filter->fmt_in.video.i_x_offset/2 +
1093 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1097 /* Draw until we reach the bottom of the subtitle */
1098 for( i_y = 0; i_y < i_height; i_y++,
1099 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1100 p_src2_y += i_src2_pitch )
1102 /* Completely opaque. Completely overwrite underlying pixel */
1103 p_filter->p_libvlc->pf_memcpy( p_dst_y, p_src2_y, i_width );
1104 if( b_even_scanline )
1106 p_dst_u += i_dst_pitch/2;
1107 p_dst_v += i_dst_pitch/2;
1108 p_src1_u += i_src1_pitch/2;
1109 p_src1_v += i_src1_pitch/2;
1113 p_filter->p_libvlc->pf_memcpy( p_dst_u, p_src2_u, i_width/2 );
1114 p_filter->p_libvlc->pf_memcpy( p_dst_v, p_src2_v, i_width/2 );
1116 b_even_scanline = !b_even_scanline;
1119 p_src2_u += i_src2_pitch/2;
1120 p_src2_v += i_src2_pitch/2;
1127 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1128 picture_t *p_dst_orig, picture_t *p_src,
1129 int i_x_offset, int i_y_offset,
1130 int i_width, int i_height, int i_alpha )
1132 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1133 uint8_t *p_dst, *p_src1, *p_src2_y;
1134 uint8_t *p_src2_u, *p_src2_v;
1135 int i_x, i_y, i_pix_pitch;
1138 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1139 i_dst_pitch = p_dst_pic->p->i_pitch;
1140 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1141 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1142 p_dst_pic->p->i_pitch *
1143 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1145 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1146 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1147 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1148 p_dst_orig->p->i_pitch *
1149 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1151 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1152 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1153 p_filter->fmt_in.video.i_x_offset +
1154 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1155 p_src2_u = p_src->p[U_PLANE].p_pixels +
1156 p_filter->fmt_in.video.i_x_offset/2 +
1157 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1158 p_src2_v = p_src->p[V_PLANE].p_pixels +
1159 p_filter->fmt_in.video.i_x_offset/2 +
1160 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1162 #define MAX_TRANS 255
1163 #define TRANS_BITS 8
1165 /* Draw until we reach the bottom of the subtitle */
1166 for( i_y = 0; i_y < i_height; i_y++,
1167 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1168 p_src2_y += i_src2_pitch )
1170 /* Draw until we reach the end of the line */
1171 for( i_x = 0; i_x < i_width; i_x++ )
1173 if( i_alpha == MAX_TRANS )
1175 /* Completely opaque. Completely overwrite underlying pixel */
1176 yuv_to_rgb( &r, &g, &b,
1177 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1179 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1184 /* FIXME: do the blending */
1185 yuv_to_rgb( &r, &g, &b,
1186 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1188 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1192 p_src2_u += i_src2_pitch/2;
1193 p_src2_v += i_src2_pitch/2;
1203 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1204 picture_t *p_dst_orig, picture_t *p_src,
1205 int i_x_offset, int i_y_offset,
1206 int i_width, int i_height, int i_alpha )
1208 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1209 uint8_t *p_dst, *p_src1, *p_src2_y;
1210 uint8_t *p_src2_u, *p_src2_v;
1211 int i_x, i_y, i_pix_pitch;
1214 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1215 i_dst_pitch = p_dst_pic->p->i_pitch;
1216 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1217 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1218 p_dst_pic->p->i_pitch *
1219 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1221 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1222 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1223 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1224 p_dst_orig->p->i_pitch *
1225 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1227 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1228 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1229 p_filter->fmt_in.video.i_x_offset +
1230 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1231 p_src2_u = p_src->p[U_PLANE].p_pixels +
1232 p_filter->fmt_in.video.i_x_offset/2 +
1233 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1234 p_src2_v = p_src->p[V_PLANE].p_pixels +
1235 p_filter->fmt_in.video.i_x_offset/2 +
1236 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1238 #define MAX_TRANS 255
1239 #define TRANS_BITS 8
1241 /* Draw until we reach the bottom of the subtitle */
1242 for( i_y = 0; i_y < i_height; i_y++,
1243 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1244 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1245 p_src2_v += i_src2_pitch )
1247 /* Draw until we reach the end of the line */
1248 for( i_x = 0; i_x < i_width; i_x++ )
1250 if( i_alpha == MAX_TRANS )
1252 /* Completely opaque. Completely overwrite underlying pixel */
1253 yuv_to_rgb( &r, &g, &b,
1254 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1256 p_dst[i_x * i_pix_pitch] = r;
1257 p_dst[i_x * i_pix_pitch + 1] = g;
1258 p_dst[i_x * i_pix_pitch + 2] = b;
1263 yuv_to_rgb( &r, &g, &b,
1264 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1266 p_dst[i_x * i_pix_pitch] = ( r * i_alpha +
1267 (uint16_t)p_src1[i_x * i_pix_pitch] *
1268 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1269 p_dst[i_x * i_pix_pitch + 1] = ( g * i_alpha +
1270 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1271 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1272 p_dst[i_x * i_pix_pitch + 2] = ( b * i_alpha +
1273 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1274 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1278 p_src2_u += i_src2_pitch/2;
1279 p_src2_v += i_src2_pitch/2;
1289 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1290 picture_t *p_dst_orig, picture_t *p_src,
1291 int i_x_offset, int i_y_offset,
1292 int i_width, int i_height, int i_alpha )
1294 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1295 uint8_t *p_dst, *p_src1, *p_src2_y;
1296 uint8_t *p_src2_u, *p_src2_v;
1297 int i_x, i_y, i_pix_pitch;
1298 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1299 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1301 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1307 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1313 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1321 i_dst_pitch = p_dst_pic->p->i_pitch;
1322 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1323 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1324 p_dst_pic->p->i_pitch *
1325 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1327 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1328 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1329 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1330 p_dst_orig->p->i_pitch *
1331 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1333 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1334 p_src2_y = p_src->p[Y_PLANE].p_pixels +
1335 p_filter->fmt_in.video.i_x_offset +
1336 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1337 p_src2_u = p_src->p[U_PLANE].p_pixels +
1338 p_filter->fmt_in.video.i_x_offset/2 +
1339 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1340 p_src2_v = p_src->p[V_PLANE].p_pixels +
1341 p_filter->fmt_in.video.i_x_offset/2 +
1342 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1344 i_width &= ~1; /* Needs to be a multiple of 2 */
1346 #define MAX_TRANS 255
1347 #define TRANS_BITS 8
1349 /* Draw until we reach the bottom of the subtitle */
1350 for( i_y = 0; i_y < i_height; i_y++,
1351 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1352 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1353 p_src2_v += i_src2_pitch )
1355 /* Draw until we reach the end of the line */
1356 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1358 if( i_alpha == MAX_TRANS )
1360 /* Completely opaque. Completely overwrite underlying pixel */
1361 p_dst[i_x * 2 + i_l_offset] = p_src2_y[i_x];
1365 p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x/2];
1366 p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x/2];
1372 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1373 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_alpha) )
1378 uint16_t i_u = p_src2_u[i_x/2];
1379 uint16_t i_v = p_src2_v[i_x/2];
1380 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_alpha +
1381 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_alpha) )
1383 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_alpha +
1384 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_alpha) )
1391 p_src2_u += i_src2_pitch/2;
1392 p_src2_v += i_src2_pitch/2;
1402 /***********************************************************************
1404 ***********************************************************************/
1405 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1406 picture_t *p_dst_orig, picture_t *p_src,
1407 int i_x_offset, int i_y_offset,
1408 int i_width, int i_height, int i_alpha )
1410 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1411 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1412 uint8_t *p_src1_u, *p_dst_u;
1413 uint8_t *p_src1_v, *p_dst_v;
1414 int i_x, i_y, i_trans;
1415 vlc_bool_t b_even_scanline = i_y_offset % 2;
1417 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1418 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1419 p_filter->fmt_out.video.i_x_offset +
1420 p_dst->p[Y_PLANE].i_pitch *
1421 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1422 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1423 p_filter->fmt_out.video.i_x_offset/2 +
1424 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1425 p_dst->p[U_PLANE].i_pitch;
1426 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1427 p_filter->fmt_out.video.i_x_offset/2 +
1428 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1429 p_dst->p[V_PLANE].i_pitch;
1431 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1432 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1433 p_filter->fmt_out.video.i_x_offset +
1434 p_dst_orig->p[Y_PLANE].i_pitch *
1435 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1436 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1437 p_filter->fmt_out.video.i_x_offset/2 +
1438 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1439 p_dst_orig->p[U_PLANE].i_pitch;
1440 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1441 p_filter->fmt_out.video.i_x_offset/2 +
1442 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1443 p_dst_orig->p[V_PLANE].i_pitch;
1445 i_src2_pitch = p_src->p->i_pitch;
1446 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1447 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1449 #define MAX_TRANS 255
1450 #define TRANS_BITS 8
1451 #define p_trans p_src2
1452 #define p_pal p_filter->fmt_in.video.p_palette->palette
1454 /* Draw until we reach the bottom of the subtitle */
1455 for( i_y = 0; i_y < i_height; i_y++,
1456 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1457 p_src2 += i_src2_pitch,
1458 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1459 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1460 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1461 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1463 b_even_scanline = !b_even_scanline;
1465 /* Draw until we reach the end of the line */
1466 for( i_x = 0; i_x < i_width; i_x++ )
1468 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1471 /* Completely transparent. Don't change pixel */
1474 else if( i_trans == MAX_TRANS )
1476 /* Completely opaque. Completely overwrite underlying pixel */
1477 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
1479 if( b_even_scanline && ((i_x % 2) == 0) )
1481 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
1482 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
1488 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
1489 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1492 if( b_even_scanline && ((i_x % 2) == 0) )
1494 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
1495 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1497 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
1498 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1512 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1513 picture_t *p_dst_orig, picture_t *p_src,
1514 int i_x_offset, int i_y_offset,
1515 int i_width, int i_height, int i_alpha )
1517 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1518 uint8_t *p_src1, *p_src2, *p_dst;
1519 int i_x, i_y, i_pix_pitch, i_trans;
1520 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1521 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1523 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1529 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1535 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1543 i_dst_pitch = p_dst_pic->p->i_pitch;
1544 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1545 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1546 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1548 i_src1_pitch = p_dst_orig->p->i_pitch;
1549 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1550 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1551 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1553 i_src2_pitch = p_src->p->i_pitch;
1554 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1555 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1557 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1559 #define MAX_TRANS 255
1560 #define TRANS_BITS 8
1561 #define p_trans p_src2
1562 #define p_pal p_filter->fmt_in.video.p_palette->palette
1564 /* Draw until we reach the bottom of the subtitle */
1565 for( i_y = 0; i_y < i_height; i_y++,
1566 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1568 /* Draw until we reach the end of the line */
1569 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1571 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1574 /* Completely transparent. Don't change pixel */
1576 else if( i_trans == MAX_TRANS )
1578 /* Completely opaque. Completely overwrite underlying pixel */
1579 p_dst[i_x * 2 + i_l_offset] = p_pal[p_src2[i_x]][0];
1583 if( p_trans[i_x+1] > 0xaa )
1585 p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1586 p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1590 p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1591 p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1598 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1599 i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1600 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1606 if( p_trans[i_x+1] > 0xaa )
1608 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1609 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1613 i_u = p_pal[p_src2[i_x]][1];
1614 i_v = p_pal[p_src2[i_x]][2];
1617 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1618 i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1619 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1620 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1621 i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1622 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1636 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1637 picture_t *p_dst_orig, picture_t *p_src,
1638 int i_x_offset, int i_y_offset,
1639 int i_width, int i_height, int i_alpha )
1641 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1642 uint8_t *p_src1, *p_src2, *p_dst;
1643 int i_x, i_y, i_pix_pitch, i_trans;
1645 video_palette_t rgbpalette;
1647 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1648 i_dst_pitch = p_dst_pic->p->i_pitch;
1649 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1650 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1651 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1653 i_src1_pitch = p_dst_orig->p->i_pitch;
1654 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1655 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1656 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1658 i_src2_pitch = p_src->p->i_pitch;
1659 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1660 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1662 #define MAX_TRANS 255
1663 #define TRANS_BITS 8
1664 #define p_trans p_src2
1665 #define p_pal p_filter->fmt_in.video.p_palette->palette
1666 #define rgbpal rgbpalette.palette
1668 /* Convert palette first */
1669 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1672 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1674 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1676 *(uint16_t *)rgbpal[i_y] =
1677 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1681 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1685 /* Draw until we reach the bottom of the subtitle */
1686 for( i_y = 0; i_y < i_height; i_y++,
1687 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1689 /* Draw until we reach the end of the line */
1690 for( i_x = 0; i_x < i_width; i_x++ )
1692 i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1695 /* Completely transparent. Don't change pixel */
1698 else if( i_trans == MAX_TRANS ||
1699 p_filter->fmt_out.video.i_chroma ==
1700 VLC_FOURCC('R','V','1','6') )
1702 /* Completely opaque. Completely overwrite underlying pixel */
1703 p_dst[i_x * i_pix_pitch] = rgbpal[p_src2[i_x]][0];
1704 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1705 if( p_filter->fmt_out.video.i_chroma !=
1706 VLC_FOURCC('R','V','1','6') )
1707 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1712 p_dst[i_x * i_pix_pitch] = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1713 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1714 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1715 p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1716 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1717 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1718 p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1719 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1720 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1733 /***********************************************************************
1735 ***********************************************************************/
1736 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1737 picture_t *p_dst_orig, picture_t *p_src,
1738 int i_x_offset, int i_y_offset,
1739 int i_width, int i_height, int i_alpha )
1741 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1742 uint8_t *p_src1_y, *p_dst_y;
1743 uint8_t *p_src1_u, *p_dst_u;
1744 uint8_t *p_src1_v, *p_dst_v;
1746 int i_x, i_y, i_trans;
1749 vlc_bool_t b_even_scanline = i_y_offset % 2;
1751 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1752 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1753 p_filter->fmt_out.video.i_x_offset +
1754 p_dst->p[Y_PLANE].i_pitch *
1755 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1756 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1757 p_filter->fmt_out.video.i_x_offset/2 +
1758 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1759 p_dst->p[U_PLANE].i_pitch;
1760 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1761 p_filter->fmt_out.video.i_x_offset/2 +
1762 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1763 p_dst->p[V_PLANE].i_pitch;
1765 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1766 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1767 p_filter->fmt_out.video.i_x_offset +
1768 p_dst_orig->p[Y_PLANE].i_pitch *
1769 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1770 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1771 p_filter->fmt_out.video.i_x_offset/2 +
1772 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1773 p_dst_orig->p[U_PLANE].i_pitch;
1774 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1775 p_filter->fmt_out.video.i_x_offset/2 +
1776 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1777 p_dst_orig->p[V_PLANE].i_pitch;
1779 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1780 i_src2_pitch = p_src->p->i_pitch;
1781 p_src2 = p_src->p->p_pixels +
1782 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1783 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1786 #define MAX_TRANS 255
1787 #define TRANS_BITS 8
1789 /* Draw until we reach the bottom of the subtitle */
1790 for( i_y = 0; i_y < i_height; i_y++,
1791 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1792 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1793 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1794 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1795 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1796 p_src2 += i_src2_pitch )
1798 b_even_scanline = !b_even_scanline;
1800 /* Draw until we reach the end of the line */
1801 for( i_x = 0; i_x < i_width; i_x++ )
1803 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1804 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1805 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1806 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1809 /* Completely transparent. Don't change pixel */
1812 else if( i_trans == MAX_TRANS )
1814 /* Completely opaque. Completely overwrite underlying pixel */
1815 rgb_to_yuv( &y, &u, &v, R, G, B );
1818 if( b_even_scanline && i_x % 2 == 0 )
1827 rgb_to_yuv( &y, &u, &v, R, G, B );
1828 p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1829 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1832 if( b_even_scanline && i_x % 2 == 0 )
1834 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1835 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1837 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1838 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1853 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1854 picture_t *p_dst_orig, picture_t *p_src,
1855 int i_x_offset, int i_y_offset,
1856 int i_width, int i_height, int i_alpha )
1858 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1859 uint8_t *p_dst, *p_src1, *p_src2;
1860 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1862 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1863 i_dst_pitch = p_dst_pic->p->i_pitch;
1864 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1865 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1866 p_dst_pic->p->i_pitch *
1867 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1869 i_src1_pitch = p_dst_orig->p->i_pitch;
1870 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1871 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1872 p_dst_orig->p->i_pitch *
1873 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1875 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1876 i_src2_pitch = p_src->p->i_pitch;
1877 p_src2 = p_src->p->p_pixels +
1878 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1879 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1881 #define MAX_TRANS 255
1882 #define TRANS_BITS 8
1884 /* Draw until we reach the bottom of the subtitle */
1885 for( i_y = 0; i_y < i_height; i_y++,
1886 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1888 /* Draw until we reach the end of the line */
1889 for( i_x = 0; i_x < i_width; i_x++ )
1891 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1892 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1893 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1894 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1897 /* Completely transparent. Don't change pixel */
1900 else if( i_trans == MAX_TRANS )
1902 /* Completely opaque. Completely overwrite underlying pixel */
1903 p_dst[i_x * i_pix_pitch + 0] = R;
1904 p_dst[i_x * i_pix_pitch + 1] = G;
1905 p_dst[i_x * i_pix_pitch + 2] = B;
1910 p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1911 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1912 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1913 p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1914 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1915 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1916 p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1917 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1918 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1931 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1932 picture_t *p_dst_orig, picture_t *p_src,
1933 int i_x_offset, int i_y_offset,
1934 int i_width, int i_height, int i_alpha )
1936 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1937 uint8_t *p_dst, *p_src1, *p_src2;
1938 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1941 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1942 i_dst_pitch = p_dst_pic->p->i_pitch;
1943 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1944 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1945 p_dst_pic->p->i_pitch *
1946 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1948 i_src1_pitch = p_dst_orig->p->i_pitch;
1949 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1950 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1951 p_dst_orig->p->i_pitch *
1952 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1954 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1955 i_src2_pitch = p_src->p->i_pitch;
1956 p_src2 = p_src->p->p_pixels +
1957 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1958 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1960 #define MAX_TRANS 255
1961 #define TRANS_BITS 8
1963 /* Draw until we reach the bottom of the subtitle */
1964 for( i_y = 0; i_y < i_height; i_y++,
1965 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1967 /* Draw until we reach the end of the line */
1968 for( i_x = 0; i_x < i_width; i_x++ )
1970 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
1971 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
1972 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
1973 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1976 /* Completely transparent. Don't change pixel */
1979 else if( i_trans == MAX_TRANS )
1981 /* Completely opaque. Completely overwrite underlying pixel */
1982 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1987 i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1988 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1989 ( ( ( (R >> 3)*i_trans
1990 + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1991 >> TRANS_BITS ) << 11 )
1992 | ( ( ( (G >> 2)*i_trans
1993 + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1994 >> TRANS_BITS ) << 5 )
1995 | ( ( ( (B >> 3)*i_trans
1996 + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
2010 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
2011 picture_t *p_dst_orig, picture_t *p_src,
2012 int i_x_offset, int i_y_offset,
2013 int i_width, int i_height, int i_alpha )
2015 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
2016 uint8_t *p_dst, *p_src1, *p_src2;
2018 int i_x, i_y, i_pix_pitch, i_trans;
2019 vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
2020 int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
2023 if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
2029 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
2035 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
2043 i_dst_pitch = p_dst_pic->p->i_pitch;
2044 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
2045 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2046 p_dst_pic->p->i_pitch *
2047 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2049 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
2050 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
2051 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2052 p_dst_orig->p->i_pitch *
2053 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2055 i_src_pix_pitch = p_src->p->i_pixel_pitch;
2056 i_src2_pitch = p_src->p->i_pitch;
2057 p_src2 = p_src->p->p_pixels +
2058 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
2059 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
2061 i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
2063 #define MAX_TRANS 255
2064 #define TRANS_BITS 8
2066 /* Draw until we reach the bottom of the subtitle */
2067 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
2068 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
2069 p_src2 += i_src2_pitch )
2071 /* Draw until we reach the end of the line */
2072 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
2074 #define R ( p_src2[i_x * i_src_pix_pitch + 0] )
2075 #define G ( p_src2[i_x * i_src_pix_pitch + 1] )
2076 #define B ( p_src2[i_x * i_src_pix_pitch + 2] )
2077 i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
2080 /* Completely transparent. Don't change pixel */
2082 else if( i_trans == MAX_TRANS )
2084 /* Completely opaque. Completely overwrite underlying pixel */
2085 rgb_to_yuv( &y, &u, &v, R, G, B );
2086 p_dst[i_x * 2 + i_l_offset] = y;
2090 p_dst[i_x * 2 + i_u_offset] = u;
2091 p_dst[i_x * 2 + i_v_offset] = v;
2097 rgb_to_yuv( &y, &u, &v, R, G, B );
2098 p_dst[i_x * 2 + i_l_offset] = ( (uint16_t)y * i_trans +
2099 (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
2104 p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
2105 (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
2107 p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
2108 (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )