1 /*****************************************************************************
2 * blend.c: alpha blend 2 pictures together
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
7 * Author: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
28 #include <vlc/decoder.h>
29 #include "vlc_filter.h"
31 /*****************************************************************************
32 * filter_sys_t : filter descriptor
33 *****************************************************************************/
38 /****************************************************************************
40 ****************************************************************************/
41 static int OpenFilter ( vlc_object_t * );
42 static void CloseFilter( vlc_object_t * );
44 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
46 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
48 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
50 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
52 static void BlendYUY2( filter_t *, picture_t *, picture_t *, picture_t *,
54 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
56 static void BlendPalYUY2( filter_t *, picture_t *, picture_t *, picture_t *,
59 /*****************************************************************************
61 *****************************************************************************/
63 set_description( _("Video pictures blending") );
64 set_capability( "video blending", 100 );
65 set_callbacks( OpenFilter, CloseFilter );
68 /*****************************************************************************
69 * OpenFilter: probe the filter and return score
70 *****************************************************************************/
71 static int OpenFilter( vlc_object_t *p_this )
73 filter_t *p_filter = (filter_t*)p_this;
76 /* Check if we can handle that format.
77 * We could try to use a chroma filter if we can't. */
78 if( ( p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','U','V','A') &&
79 p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','U','V','P') ) ||
80 ( p_filter->fmt_out.video.i_chroma != VLC_FOURCC('I','4','2','0') &&
81 p_filter->fmt_out.video.i_chroma != VLC_FOURCC('Y','U','Y','2') &&
82 p_filter->fmt_out.video.i_chroma != VLC_FOURCC('Y','V','1','2') &&
83 p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','1','6') &&
84 p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','2','4') &&
85 p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','3','2') ) )
90 /* Allocate the memory needed to store the decoder's structure */
91 if( ( p_filter->p_sys = p_sys =
92 (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
94 msg_Err( p_filter, "out of memory" );
99 p_filter->pf_video_blend = Blend;
101 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
102 (char *)&p_filter->fmt_in.video.i_chroma,
103 (char *)&p_filter->fmt_out.video.i_chroma );
109 /****************************************************************************
110 * Blend: the whole thing
111 ****************************************************************************
112 * This function is called just after the thread is launched.
113 ****************************************************************************/
114 static void Blend( filter_t *p_filter, picture_t *p_dst,
115 picture_t *p_dst_orig, picture_t *p_src,
116 int i_x_offset, int i_y_offset )
118 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
119 ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('I','4','2','0') ||
120 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ) )
122 BlendI420( p_filter, p_dst, p_dst_orig, p_src,
123 i_x_offset, i_y_offset );
126 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
127 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
129 BlendYUY2( p_filter, p_dst, p_dst_orig, p_src,
130 i_x_offset, i_y_offset );
133 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
134 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
136 BlendR16( p_filter, p_dst, p_dst_orig, p_src,
137 i_x_offset, i_y_offset );
140 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
141 ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','2','4') ||
142 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','3','2') ) )
144 BlendR24( p_filter, p_dst, p_dst_orig, p_src,
145 i_x_offset, i_y_offset );
148 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','P') &&
149 ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('I','4','2','0') ||
150 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ) )
152 BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
153 i_x_offset, i_y_offset );
156 if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','P') &&
157 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
159 BlendPalYUY2( p_filter, p_dst, p_dst_orig, p_src,
160 i_x_offset, i_y_offset );
164 msg_Dbg( p_filter, "no matching alpha blending routine" );
167 static void BlendI420( 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 )
171 filter_sys_t *p_sys = p_filter->p_sys;
172 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
173 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
174 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
175 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
177 int i_width, i_height, i_x, i_y;
178 vlc_bool_t b_even_scanline = i_y_offset % 2;
180 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
181 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
182 p_filter->fmt_out.video.i_x_offset +
183 p_dst->p[Y_PLANE].i_pitch *
184 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
185 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
186 p_filter->fmt_out.video.i_x_offset/2 +
187 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
188 p_dst->p[U_PLANE].i_pitch;
189 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
190 p_filter->fmt_out.video.i_x_offset/2 +
191 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
192 p_dst->p[V_PLANE].i_pitch;
194 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
195 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
196 p_filter->fmt_out.video.i_x_offset +
197 p_dst_orig->p[Y_PLANE].i_pitch *
198 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
199 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
200 p_filter->fmt_out.video.i_x_offset/2 +
201 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
202 p_dst_orig->p[U_PLANE].i_pitch;
203 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
204 p_filter->fmt_out.video.i_x_offset/2 +
205 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
206 p_dst_orig->p[V_PLANE].i_pitch;
208 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
209 p_src2_y = p_src->p[Y_PLANE].p_pixels +
210 p_filter->fmt_in.video.i_x_offset +
211 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
212 p_src2_u = p_src->p[U_PLANE].p_pixels +
213 p_filter->fmt_in.video.i_x_offset/2 +
214 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
215 p_src2_v = p_src->p[V_PLANE].p_pixels +
216 p_filter->fmt_in.video.i_x_offset/2 +
217 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
219 p_trans = p_src->p[A_PLANE].p_pixels +
220 p_filter->fmt_in.video.i_x_offset +
221 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
223 i_width = __MIN( p_filter->fmt_out.video.i_visible_width - i_x_offset,
224 p_filter->fmt_in.video.i_visible_width );
226 i_height = __MIN( p_filter->fmt_out.video.i_visible_height - i_y_offset,
227 p_filter->fmt_in.video.i_visible_height );
229 #define MAX_TRANS 255
232 /* Draw until we reach the bottom of the subtitle */
233 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
234 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
235 p_src2_y += i_src2_pitch,
236 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
237 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
238 p_src2_u += i_src2_pitch,
239 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
240 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
241 p_src2_v += i_src2_pitch )
243 b_even_scanline = !b_even_scanline;
245 /* Draw until we reach the end of the line */
246 for( i_x = 0; i_x < i_width; i_x++ )
250 /* Completely transparent. Don't change pixel */
253 else if( p_trans[i_x] == MAX_TRANS )
255 /* Completely opaque. Completely overwrite underlying pixel */
256 p_dst_y[i_x] = p_src2_y[i_x];
258 if( b_even_scanline && i_x % 2 == 0 )
260 p_dst_u[i_x/2] = p_src2_u[i_x];
261 p_dst_v[i_x/2] = p_src2_v[i_x];
267 p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * p_trans[i_x] +
268 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - p_trans[i_x]) )
271 if( b_even_scanline && i_x % 2 == 0 )
273 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * p_trans[i_x] +
274 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - p_trans[i_x]) )
276 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * p_trans[i_x] +
277 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - p_trans[i_x]) )
289 static inline void yuv_to_rgb( int *r, int *g, int *b,
290 uint8_t y1, uint8_t u1, uint8_t v1 )
292 /* macros used for YUV pixel conversions */
293 # define SCALEBITS 10
294 # define ONE_HALF (1 << (SCALEBITS - 1))
295 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
296 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
298 int y, cb, cr, r_add, g_add, b_add;
302 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
303 g_add = - FIX(0.34414*255.0/224.0) * cb
304 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
305 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
306 y = (y1 - 16) * FIX(255.0/219.0);
307 *r = CLAMP((y + r_add) >> SCALEBITS);
308 *g = CLAMP((y + g_add) >> SCALEBITS);
309 *b = CLAMP((y + b_add) >> SCALEBITS);
312 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
313 picture_t *p_dst_orig, picture_t *p_src,
314 int i_x_offset, int i_y_offset )
316 filter_sys_t *p_sys = p_filter->p_sys;
317 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
318 uint8_t *p_dst, *p_src1, *p_src2_y;
319 uint8_t *p_src2_u, *p_src2_v;
321 int i_width, i_height, i_x, i_y, i_pix_pitch;
324 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
325 i_dst_pitch = p_dst_pic->p->i_pitch;
326 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
327 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
328 p_dst_pic->p->i_pitch *
329 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
331 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
332 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
333 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
334 p_dst_orig->p->i_pitch *
335 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
337 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
338 p_src2_y = p_src->p[Y_PLANE].p_pixels +
339 p_filter->fmt_in.video.i_x_offset +
340 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
341 p_src2_u = p_src->p[U_PLANE].p_pixels +
342 p_filter->fmt_in.video.i_x_offset/2 +
343 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
344 p_src2_v = p_src->p[V_PLANE].p_pixels +
345 p_filter->fmt_in.video.i_x_offset/2 +
346 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
348 p_trans = p_src->p[A_PLANE].p_pixels +
349 p_filter->fmt_in.video.i_x_offset +
350 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
352 i_width = __MIN( p_filter->fmt_out.video.i_visible_width - i_x_offset,
353 p_filter->fmt_in.video.i_visible_width );
355 i_height = __MIN( p_filter->fmt_out.video.i_visible_height - i_y_offset,
356 p_filter->fmt_in.video.i_visible_height );
358 #define MAX_TRANS 255
361 /* Draw until we reach the bottom of the subtitle */
362 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
363 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
364 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
365 p_src2_v += i_src2_pitch )
367 /* Draw until we reach the end of the line */
368 for( i_x = 0; i_x < i_width; i_x++ )
372 /* Completely transparent. Don't change pixel */
375 else if( p_trans[i_x] == MAX_TRANS )
377 /* Completely opaque. Completely overwrite underlying pixel */
378 yuv_to_rgb( &r, &g, &b,
379 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
381 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
386 yuv_to_rgb( &r, &g, &b,
387 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
389 ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
399 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
400 picture_t *p_dst_orig, picture_t *p_src,
401 int i_x_offset, int i_y_offset )
403 filter_sys_t *p_sys = p_filter->p_sys;
404 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
405 uint8_t *p_dst, *p_src1, *p_src2_y;
406 uint8_t *p_src2_u, *p_src2_v;
408 int i_width, i_height, i_x, i_y, i_pix_pitch;
411 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
412 i_dst_pitch = p_dst_pic->p->i_pitch;
413 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
414 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
415 p_dst_pic->p->i_pitch *
416 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
418 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
419 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
420 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
421 p_dst_orig->p->i_pitch *
422 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
424 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
425 p_src2_y = p_src->p[Y_PLANE].p_pixels +
426 p_filter->fmt_in.video.i_x_offset +
427 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
428 p_src2_u = p_src->p[U_PLANE].p_pixels +
429 p_filter->fmt_in.video.i_x_offset/2 +
430 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
431 p_src2_v = p_src->p[V_PLANE].p_pixels +
432 p_filter->fmt_in.video.i_x_offset/2 +
433 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
435 p_trans = p_src->p[A_PLANE].p_pixels +
436 p_filter->fmt_in.video.i_x_offset +
437 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
439 i_width = __MIN( p_filter->fmt_out.video.i_visible_width - i_x_offset,
440 p_filter->fmt_in.video.i_visible_width );
442 i_height = __MIN( p_filter->fmt_out.video.i_visible_height - i_y_offset,
443 p_filter->fmt_in.video.i_visible_height );
445 #define MAX_TRANS 255
448 /* Draw until we reach the bottom of the subtitle */
449 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
450 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
451 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
452 p_src2_v += i_src2_pitch )
454 /* Draw until we reach the end of the line */
455 for( i_x = 0; i_x < i_width; i_x++ )
459 /* Completely transparent. Don't change pixel */
462 else if( p_trans[i_x] == MAX_TRANS )
464 /* Completely opaque. Completely overwrite underlying pixel */
465 yuv_to_rgb( &r, &g, &b,
466 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
468 p_dst[i_x * i_pix_pitch] = r;
469 p_dst[i_x * i_pix_pitch + 1] = g;
470 p_dst[i_x * i_pix_pitch + 2] = b;
475 yuv_to_rgb( &r, &g, &b,
476 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
478 p_dst[i_x * i_pix_pitch] = ( r * p_trans[i_x] +
479 (uint16_t)p_src1[i_x * i_pix_pitch] *
480 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
481 p_dst[i_x * i_pix_pitch + 1] = ( g * p_trans[i_x] +
482 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
483 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
484 p_dst[i_x * i_pix_pitch + 2] = ( b * p_trans[i_x] +
485 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
486 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
496 static void BlendYUY2( filter_t *p_filter, picture_t *p_dst_pic,
497 picture_t *p_dst_orig, picture_t *p_src,
498 int i_x_offset, int i_y_offset )
500 filter_sys_t *p_sys = p_filter->p_sys;
501 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
502 uint8_t *p_dst, *p_src1, *p_src2_y;
503 uint8_t *p_src2_u, *p_src2_v;
505 int i_width, i_height, i_x, i_y, i_pix_pitch;
508 i_dst_pitch = p_dst_pic->p->i_pitch;
509 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
510 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
511 p_dst_pic->p->i_pitch *
512 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
514 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
515 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
516 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
517 p_dst_orig->p->i_pitch *
518 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
520 i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
521 p_src2_y = p_src->p[Y_PLANE].p_pixels +
522 p_filter->fmt_in.video.i_x_offset +
523 p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
524 p_src2_u = p_src->p[U_PLANE].p_pixels +
525 p_filter->fmt_in.video.i_x_offset/2 +
526 p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
527 p_src2_v = p_src->p[V_PLANE].p_pixels +
528 p_filter->fmt_in.video.i_x_offset/2 +
529 p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
531 p_trans = p_src->p[A_PLANE].p_pixels +
532 p_filter->fmt_in.video.i_x_offset +
533 p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
535 i_width = __MIN( p_filter->fmt_out.video.i_visible_width - i_x_offset,
536 p_filter->fmt_in.video.i_visible_width );
538 i_height = __MIN( p_filter->fmt_out.video.i_visible_height - i_y_offset,
539 p_filter->fmt_in.video.i_visible_height );
541 #define MAX_TRANS 255
544 /* Draw until we reach the bottom of the subtitle */
545 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
546 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
547 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
548 p_src2_v += i_src2_pitch )
550 /* Draw until we reach the end of the line */
551 for( i_x = 0; i_x < i_width; i_x += 2 )
555 /* Completely transparent. Don't change pixel */
557 else if( p_trans[i_x] == MAX_TRANS )
559 /* Completely opaque. Completely overwrite underlying pixel */
560 p_dst[i_x * 2] = p_src2_y[i_x];
561 p_dst[i_x * 2 + 1] = p_src2_u[i_x];
562 p_dst[i_x * 2 + 3] = p_src2_v[i_x];
567 p_dst[i_x * 2] = ( (uint16_t)p_src2_y[i_x] * p_trans[i_x] +
568 (uint16_t)p_src1[i_x * 2] *
569 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
570 p_dst[i_x * 2 + 1] = ( (uint16_t)p_src2_u[i_x] * p_trans[i_x] +
571 (uint16_t)p_src1[i_x * 2 + 1] *
572 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
573 p_dst[i_x * 2 + 3] = ( (uint16_t)p_src2_v[i_x] * p_trans[i_x] +
574 (uint16_t)p_src1[i_x * 2 + 3] *
575 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
578 if( !p_trans[i_x+1] )
580 /* Completely transparent. Don't change pixel */
582 else if( p_trans[i_x+1] == MAX_TRANS )
584 /* Completely opaque. Completely overwrite underlying pixel */
585 p_dst[i_x * 2 + 2] = p_src2_y[i_x + 1];
590 p_dst[i_x * 2 + 2] = ( (uint16_t)p_src2_y[i_x+1] *
591 p_trans[i_x+1] + (uint16_t)p_src1[i_x * 2 + 2] *
592 (MAX_TRANS - p_trans[i_x+1]) ) >> TRANS_BITS;
603 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
604 picture_t *p_dst_orig, picture_t *p_src,
605 int i_x_offset, int i_y_offset )
607 filter_sys_t *p_sys = p_filter->p_sys;
608 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
609 uint8_t *p_src1_y, *p_src2, *p_dst_y;
610 uint8_t *p_src1_u, *p_dst_u;
611 uint8_t *p_src1_v, *p_dst_v;
612 int i_width, i_height, i_x, i_y;
613 vlc_bool_t b_even_scanline = i_y_offset % 2;
615 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
616 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
617 p_filter->fmt_out.video.i_x_offset +
618 p_dst->p[Y_PLANE].i_pitch *
619 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
620 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
621 p_filter->fmt_out.video.i_x_offset/2 +
622 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
623 p_dst->p[U_PLANE].i_pitch;
624 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
625 p_filter->fmt_out.video.i_x_offset/2 +
626 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
627 p_dst->p[V_PLANE].i_pitch;
629 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
630 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
631 p_filter->fmt_out.video.i_x_offset +
632 p_dst_orig->p[Y_PLANE].i_pitch *
633 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
634 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
635 p_filter->fmt_out.video.i_x_offset/2 +
636 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
637 p_dst_orig->p[U_PLANE].i_pitch;
638 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
639 p_filter->fmt_out.video.i_x_offset/2 +
640 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
641 p_dst_orig->p[V_PLANE].i_pitch;
643 i_src2_pitch = p_src->p->i_pitch;
644 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
645 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
647 i_width = __MIN( p_filter->fmt_out.video.i_visible_width - i_x_offset,
648 p_filter->fmt_in.video.i_visible_width );
650 i_height = __MIN( p_filter->fmt_out.video.i_visible_height - i_y_offset,
651 p_filter->fmt_in.video.i_visible_height );
653 #define MAX_TRANS 255
655 #define p_trans p_src2
656 #define p_pal p_filter->fmt_in.video.p_palette->palette
658 /* Draw until we reach the bottom of the subtitle */
659 for( i_y = 0; i_y < i_height; i_y++,
660 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
661 p_src2 += i_src2_pitch,
662 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
663 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
664 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
665 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
667 b_even_scanline = !b_even_scanline;
669 /* Draw until we reach the end of the line */
670 for( i_x = 0; i_x < i_width; i_x++ )
672 if( !p_pal[p_trans[i_x]][3] )
674 /* Completely transparent. Don't change pixel */
677 else if( p_pal[p_trans[i_x]][3] == MAX_TRANS )
679 /* Completely opaque. Completely overwrite underlying pixel */
680 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
682 if( b_even_scanline && i_x % 2 == 0 )
684 p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
685 p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
691 p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
692 p_pal[p_trans[i_x]][3] + (uint16_t)p_src1_y[i_x] *
693 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
695 if( b_even_scanline && i_x % 2 == 0 )
697 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] *
698 p_pal[p_trans[i_x]][3] + (uint16_t)p_src1_u[i_x/2] *
699 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
700 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] *
701 p_pal[p_trans[i_x]][3] + (uint16_t)p_src1_v[i_x/2] *
702 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
715 static void BlendPalYUY2( filter_t *p_filter, picture_t *p_dst_pic,
716 picture_t *p_dst_orig, picture_t *p_src,
717 int i_x_offset, int i_y_offset )
719 filter_sys_t *p_sys = p_filter->p_sys;
720 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
721 uint8_t *p_src1, *p_src2, *p_dst;
722 int i_width, i_height, i_x, i_y, i_pix_pitch;
725 i_dst_pitch = p_dst_pic->p->i_pitch;
726 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
727 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
728 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
730 i_src1_pitch = p_dst_orig->p->i_pitch;
731 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
732 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
733 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
735 i_src2_pitch = p_src->p->i_pitch;
736 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
737 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
739 i_width = __MIN( p_filter->fmt_out.video.i_visible_width - i_x_offset,
740 p_filter->fmt_in.video.i_visible_width );
742 i_height = __MIN( p_filter->fmt_out.video.i_visible_height - i_y_offset,
743 p_filter->fmt_in.video.i_visible_height );
745 #define MAX_TRANS 255
747 #define p_trans p_src2
748 #define p_pal p_filter->fmt_in.video.p_palette->palette
750 /* Draw until we reach the bottom of the subtitle */
751 for( i_y = 0; i_y < i_height; i_y++,
752 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
754 /* Draw until we reach the end of the line */
755 for( i_x = 0; i_x < i_width; i_x += 2 )
757 if( !p_pal[p_trans[i_x]][3] )
759 /* Completely transparent. Don't change pixel */
761 else if( p_pal[p_trans[i_x]][3] == MAX_TRANS )
763 /* Completely opaque. Completely overwrite underlying pixel */
764 p_dst[i_x * 2] = p_pal[p_src2[i_x]][0];
765 p_dst[i_x * 2 + 1] = p_pal[p_src2[i_x]][1];
766 p_dst[i_x * 2 + 3] = p_pal[p_src2[i_x]][2];
771 p_dst[i_x * 2] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
772 p_pal[p_trans[i_x]][3] + (uint16_t)p_src1[i_x * 2] *
773 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
774 p_dst[i_x * 2 + 1] = ( (uint16_t)p_pal[p_src2[i_x]][1] *
775 p_pal[p_trans[i_x]][3] + (uint16_t)p_src1[i_x * 2 + 1] *
776 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
777 p_dst[i_x * 2 + 3] = ( (uint16_t)p_pal[p_src2[i_x]][2] *
778 p_pal[p_trans[i_x]][3] + (uint16_t)p_src1[i_x * 2 + 3] *
779 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
782 if( !p_pal[p_trans[i_x+1]][3] )
784 /* Completely transparent. Don't change pixel */
786 else if( p_pal[p_trans[i_x+1]][3] == MAX_TRANS )
788 /* Completely opaque. Completely overwrite underlying pixel */
789 p_dst[i_x * 2 + 2] = p_pal[p_src2[i_x + 1]][0];
794 p_dst[i_x * 2 + 2] = ( (uint16_t)p_pal[p_src2[i_x+1]][0] *
795 p_pal[p_trans[i_x+1]][3] + (uint16_t)p_src1[i_x * 2 + 2] *
796 (MAX_TRANS - p_pal[p_trans[i_x+1]][3]) ) >> TRANS_BITS;
809 /*****************************************************************************
810 * CloseFilter: clean up the filter
811 *****************************************************************************/
812 static void CloseFilter( vlc_object_t *p_this )
814 filter_t *p_filter = (filter_t*)p_this;
815 filter_sys_t *p_sys = p_filter->p_sys;