1 /*****************************************************************************
2 * blend.c: alpha blend 2 pictures together
3 *****************************************************************************
4 * Copyright (C) 2003-2009 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 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 static int OpenFilter ( vlc_object_t * );
41 static void CloseFilter( vlc_object_t * );
44 set_description( N_("Video pictures blending") )
45 set_capability( "video blending", 100 )
46 set_callbacks( OpenFilter, CloseFilter )
49 /****************************************************************************
51 ****************************************************************************/
52 static void Blend( filter_t *, picture_t *, const picture_t *,
56 static void BlendYUVAI420( filter_t *, picture_t *, const picture_t *,
57 int, int, int, int, int );
58 static void BlendYUVARV16( filter_t *, picture_t *, const picture_t *,
59 int, int, int, int, int );
60 static void BlendYUVARV24( filter_t *, picture_t *, const picture_t *,
61 int, int, int, int, int );
62 static void BlendYUVAYUVPacked( filter_t *, picture_t *, const picture_t *,
63 int, int, int, int, int );
66 static void BlendI420I420( filter_t *, picture_t *, const picture_t *,
67 int, int, int, int, int );
68 static void BlendI420I420_no_alpha(
69 filter_t *, picture_t *, const picture_t *,
71 static void BlendI420R16( filter_t *, picture_t *, const picture_t *,
72 int, int, int, int, int );
73 static void BlendI420R24( filter_t *, picture_t *, const picture_t *,
74 int, int, int, int, int );
75 static void BlendI420YUVPacked( filter_t *, picture_t *,
76 const picture_t *, int, int, int, int, int );
79 static void BlendPalI420( filter_t *, picture_t *, const picture_t *,
80 int, int, int, int, int );
81 static void BlendPalYUVPacked( filter_t *, picture_t *, const picture_t *,
82 int, int, int, int, int );
83 static void BlendPalRV( filter_t *, picture_t *, const picture_t *,
84 int, int, int, int, int );
87 static void BlendRGBAI420( filter_t *, picture_t *, const picture_t *,
88 int, int, int, int, int );
89 static void BlendRGBAYUVPacked( filter_t *, picture_t *,
90 const picture_t *, int, int, int, int, int );
91 static void BlendRGBAR16( filter_t *, picture_t *, const picture_t *,
92 int, int, int, int, int );
93 static void BlendRGBAR24( filter_t *, picture_t *, const picture_t *,
94 int, int, int, int, int );
96 /*****************************************************************************
97 * OpenFilter: probe the filter and return score
98 *****************************************************************************/
99 static int OpenFilter( vlc_object_t *p_this )
101 filter_t *p_filter = (filter_t*)p_this;
103 /* Check if we can handle that format.
104 * We could try to use a chroma filter if we can't. */
105 int in_chroma = p_filter->fmt_in.video.i_chroma;
106 int out_chroma = p_filter->fmt_out.video.i_chroma;
107 if( ( in_chroma != VLC_CODEC_YUVA && in_chroma != VLC_CODEC_I420 &&
108 in_chroma != VLC_CODEC_YV12 && in_chroma != VLC_CODEC_YUVP &&
109 in_chroma != VLC_CODEC_RGBA ) ||
110 ( out_chroma != VLC_CODEC_I420 && out_chroma != VLC_CODEC_YUYV &&
111 out_chroma != VLC_CODEC_YV12 && out_chroma != VLC_CODEC_UYVY &&
112 out_chroma != VLC_CODEC_YVYU && out_chroma != VLC_CODEC_RGB15 &&
113 out_chroma != VLC_CODEC_YVYU && out_chroma != VLC_CODEC_RGB16 &&
114 out_chroma != VLC_CODEC_RGB24 && out_chroma != VLC_CODEC_RGB32 ) )
120 p_filter->pf_video_blend = Blend;
122 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
123 (char *)&p_filter->fmt_in.video.i_chroma,
124 (char *)&p_filter->fmt_out.video.i_chroma );
129 /*****************************************************************************
130 * CloseFilter: clean up the filter
131 *****************************************************************************/
132 static void CloseFilter( vlc_object_t *p_this )
137 /****************************************************************************
138 * Blend: the whole thing
139 ****************************************************************************
140 * This function is called just after the thread is launched.
141 ****************************************************************************/
142 typedef void (*BlendFunction)( filter_t *,
143 picture_t *, const picture_t *,
144 int , int , int , int , int );
146 #define VLC_CODEC_PLANAR_420 { VLC_CODEC_I420, VLC_CODEC_YV12, 0 }
147 #define VLC_CODEC_PACKED_422 { VLC_CODEC_YUYV, VLC_CODEC_UYVY, VLC_CODEC_YVYU, 0 }
148 #define VLC_CODEC_RGB_16 { VLC_CODEC_RGB15, VLC_CODEC_RGB16, 0 }
149 #define VLC_CODEC_RGB_24 { VLC_CODEC_RGB24, VLC_CODEC_RGB32, 0 }
151 #define BLEND_CFG( fccSrc, fctPlanar, fctPacked, fctRgb16, fctRgb24 ) \
152 { .src = fccSrc, .p_dst = VLC_CODEC_PLANAR_420, .pf_blend = fctPlanar }, \
153 { .src = fccSrc, .p_dst = VLC_CODEC_PACKED_422, .pf_blend = fctPacked }, \
154 { .src = fccSrc, .p_dst = VLC_CODEC_RGB_16, .pf_blend = fctRgb16 }, \
155 { .src = fccSrc, .p_dst = VLC_CODEC_RGB_24, .pf_blend = fctRgb24 }
160 vlc_fourcc_t p_dst[16];
161 BlendFunction pf_blend;
164 BLEND_CFG( VLC_CODEC_YUVA, BlendYUVAI420, BlendYUVAYUVPacked, BlendYUVARV16, BlendYUVARV24 ),
166 BLEND_CFG( VLC_CODEC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ),
168 BLEND_CFG( VLC_CODEC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ),
170 BLEND_CFG( VLC_CODEC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
172 BLEND_CFG( VLC_CODEC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
177 static void Blend( filter_t *p_filter,
178 picture_t *p_dst, const picture_t *p_src,
179 int i_x_offset, int i_y_offset, int i_alpha )
181 int i_width, i_height;
186 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
187 (int)p_filter->fmt_in.video.i_visible_width);
189 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
190 (int)p_filter->fmt_in.video.i_visible_height);
192 if( i_width <= 0 || i_height <= 0 )
195 video_format_FixRgb( &p_filter->fmt_out.video );
196 video_format_FixRgb( &p_filter->fmt_in.video );
199 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
200 (char *)&p_filter->fmt_in.video.i_chroma,
201 (char *)&p_filter->fmt_out.video.i_chroma );
204 for( int i = 0; p_blend_cfg[i].src != 0; i++ )
206 if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma )
208 for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ )
210 if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma )
213 p_blend_cfg[i].pf_blend( p_filter, p_dst, p_src,
214 i_x_offset, i_y_offset,
215 i_width, i_height, i_alpha );
220 msg_Dbg( p_filter, "no matching alpha blending routine "
221 "(chroma: %4.4s -> %4.4s)",
222 (char *)&p_filter->fmt_in.video.i_chroma,
223 (char *)&p_filter->fmt_out.video.i_chroma );
226 /***********************************************************************
228 ***********************************************************************/
229 static inline uint8_t vlc_uint8( int v )
238 #define MAX_TRANS 255
241 static inline int vlc_blend( int v1, int v2, int a )
243 /* TODO bench if the tests really increase speed */
246 else if( a == MAX_TRANS )
248 return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
251 static inline int vlc_alpha( int t, int a )
255 return (t * a) / 255;
258 static inline void yuv_to_rgb( int *r, int *g, int *b,
259 uint8_t y1, uint8_t u1, uint8_t v1 )
261 /* macros used for YUV pixel conversions */
262 # define SCALEBITS 10
263 # define ONE_HALF (1 << (SCALEBITS - 1))
264 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
266 int y, cb, cr, r_add, g_add, b_add;
270 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
271 g_add = - FIX(0.34414*255.0/224.0) * cb
272 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
273 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
274 y = (y1 - 16) * FIX(255.0/219.0);
275 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
276 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
277 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
283 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
284 int r, int g, int b )
286 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
287 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
288 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
291 static uint8_t *vlc_plane_start( int *pi_pitch,
292 const picture_t *p_picture,
294 int i_x_offset, int i_y_offset,
295 const video_format_t *p_fmt,
298 const int i_pitch = p_picture->p[i_plane].i_pitch;
299 uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
301 const int i_dx = ( i_x_offset + p_fmt->i_x_offset ) / r;
302 const int i_dy = ( i_y_offset + p_fmt->i_y_offset ) / r;
306 return &p_pixels[ i_dy * i_pitch + i_dx ];
309 static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma )
311 static const struct {
315 { VLC_CODEC_YUYV, 0, 1, 3 },
316 { VLC_CODEC_UYVY, 1, 0, 2 },
317 { VLC_CODEC_YVYU, 0, 3, 1 },
322 for( i = 0; p_index[i].chroma != 0; i++ )
324 if( p_index[i].chroma == i_chroma )
327 *pi_y = p_index[i].y;
328 *pi_u = p_index[i].u;
329 *pi_v = p_index[i].v;
332 static void vlc_blend_packed( uint8_t *p_dst,
333 int i_offset0, int i_offset1, int i_offset2,
334 int c0, int c1, int c2, int i_alpha,
337 p_dst[i_offset0] = vlc_blend( c0, p_dst[i_offset0], i_alpha );
340 p_dst[i_offset1] = vlc_blend( c1, p_dst[i_offset1], i_alpha );
341 p_dst[i_offset2] = vlc_blend( c2, p_dst[i_offset2], i_alpha );
345 static void vlc_blend_rgb16( uint16_t *p_dst,
346 int R, int G, int B, int i_alpha,
347 const video_format_t *p_fmt )
349 const int i_pix = *p_dst;
350 const int r = ( i_pix & p_fmt->i_rmask ) >> p_fmt->i_lrshift;
351 const int g = ( i_pix & p_fmt->i_gmask ) >> p_fmt->i_lgshift;
352 const int b = ( i_pix & p_fmt->i_bmask ) >> p_fmt->i_lbshift;
354 *p_dst = ( vlc_blend( R >> p_fmt->i_rrshift, r, i_alpha ) << p_fmt->i_lrshift ) |
355 ( vlc_blend( G >> p_fmt->i_rgshift, g, i_alpha ) << p_fmt->i_lgshift ) |
356 ( vlc_blend( B >> p_fmt->i_rbshift, b, i_alpha ) << p_fmt->i_lbshift );
359 static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex,
360 const video_format_t *p_fmt )
362 if( p_fmt->i_chroma != VLC_CODEC_RGB24 && p_fmt->i_chroma != VLC_CODEC_RGB32 )
365 /* XXX it will works only if mask are 8 bits aligned */
366 #ifdef WORDS_BIGENDIAN
367 const int i_mask_bits = p_fmt->i_chroma == VLC_CODEC_RGB24 ? 24 : 32;
368 *pi_rindex = ( i_mask_bits - p_fmt->i_lrshift ) / 8;
369 *pi_gindex = ( i_mask_bits - p_fmt->i_lgshift ) / 8;
370 *pi_bindex = ( i_mask_bits - p_fmt->i_lbshift ) / 8;
372 *pi_rindex = p_fmt->i_lrshift / 8;
373 *pi_gindex = p_fmt->i_lgshift / 8;
374 *pi_bindex = p_fmt->i_lbshift / 8;
378 /***********************************************************************
380 ***********************************************************************/
381 static void BlendYUVAI420( filter_t *p_filter,
382 picture_t *p_dst, const picture_t *p_src,
383 int i_x_offset, int i_y_offset,
384 int i_width, int i_height, int i_alpha )
386 int i_src_pitch, i_dst_pitch;
387 uint8_t *p_src_y, *p_dst_y;
388 uint8_t *p_src_u, *p_dst_u;
389 uint8_t *p_src_v, *p_dst_v;
391 int i_x, i_y, i_trans = 0;
392 bool b_even_scanline = i_y_offset % 2;
394 p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
395 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
396 p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
397 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
398 p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
399 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
401 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
402 0, 0, &p_filter->fmt_in.video, 1 );
403 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
404 0, 0, &p_filter->fmt_in.video, 2 );
405 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
406 0, 0, &p_filter->fmt_in.video, 2 );
407 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
408 0, 0, &p_filter->fmt_in.video, 1 );
410 /* Draw until we reach the bottom of the subtitle */
411 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
412 p_dst_y += i_dst_pitch, p_src_y += i_src_pitch,
413 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
414 p_src_u += i_src_pitch,
415 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
416 p_src_v += i_src_pitch )
418 b_even_scanline = !b_even_scanline;
420 /* Draw until we reach the end of the line */
421 for( i_x = 0; i_x < i_width; i_x++ )
424 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
430 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_trans );
431 if( b_even_scanline && i_x % 2 == 0 )
433 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x], p_dst_u[i_x/2], i_trans );
434 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x], p_dst_v[i_x/2], i_trans );
440 static void BlendYUVARV16( filter_t *p_filter,
441 picture_t *p_dst_pic, const picture_t *p_src,
442 int i_x_offset, int i_y_offset,
443 int i_width, int i_height, int i_alpha )
445 int i_src_pitch, i_dst_pitch;
446 uint8_t *p_dst, *p_src_y;
447 uint8_t *p_src_u, *p_src_v;
449 int i_x, i_y, i_pix_pitch, i_trans = 0;
452 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
453 i_dst_pitch = p_dst_pic->p->i_pitch;
454 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
455 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
456 p_dst_pic->p->i_pitch *
457 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
459 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
460 0, 0, &p_filter->fmt_in.video, 1 );
461 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
462 0, 0, &p_filter->fmt_in.video, 2 );
463 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
464 0, 0, &p_filter->fmt_in.video, 2 );
465 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
466 0, 0, &p_filter->fmt_in.video, 1 );
468 /* Draw until we reach the bottom of the subtitle */
469 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
470 p_dst += i_dst_pitch,
471 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
472 p_src_v += i_src_pitch )
474 /* Draw until we reach the end of the line */
475 for( i_x = 0; i_x < i_width; i_x++ )
478 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
483 yuv_to_rgb( &r, &g, &b,
484 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
486 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
487 r, g, b, i_trans, &p_filter->fmt_out.video );
492 static void BlendYUVARV24( filter_t *p_filter,
493 picture_t *p_dst_pic, const picture_t *p_src,
494 int i_x_offset, int i_y_offset,
495 int i_width, int i_height, int i_alpha )
497 int i_src_pitch, i_dst_pitch;
498 uint8_t *p_dst, *p_src_y;
499 uint8_t *p_src_u, *p_src_v;
501 int i_x, i_y, i_pix_pitch, i_trans = 0;
504 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
505 i_dst_pitch = p_dst_pic->p->i_pitch;
506 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
507 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
508 p_dst_pic->p->i_pitch *
509 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
511 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
512 0, 0, &p_filter->fmt_in.video, 1 );
513 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
514 0, 0, &p_filter->fmt_in.video, 2 );
515 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
516 0, 0, &p_filter->fmt_in.video, 2 );
517 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
518 0, 0, &p_filter->fmt_in.video, 1 );
520 if( (i_pix_pitch == 4)
521 && (((((intptr_t)p_dst)|i_dst_pitch) /* FIXME? */
525 ** if picture pixels are 32 bits long and lines addresses are 32 bit
526 ** aligned, optimize rendering
528 uint32_t *p32_dst = (uint32_t *)p_dst;
529 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
531 int i_rshift, i_gshift, i_bshift;
532 uint32_t i_rmask, i_gmask, i_bmask;
534 i_rmask = p_filter->fmt_out.video.i_rmask;
535 i_gmask = p_filter->fmt_out.video.i_gmask;
536 i_bmask = p_filter->fmt_out.video.i_bmask;
537 i_rshift = p_filter->fmt_out.video.i_lrshift;
538 i_gshift = p_filter->fmt_out.video.i_lgshift;
539 i_bshift = p_filter->fmt_out.video.i_lbshift;
541 /* Draw until we reach the bottom of the subtitle */
542 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
543 p32_dst += i32_dst_pitch,
544 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
545 p_src_v += i_src_pitch )
547 /* Draw until we reach the end of the line */
548 for( i_x = 0; i_x < i_width; i_x++ )
551 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
555 if( i_trans == MAX_TRANS )
557 /* Completely opaque. Completely overwrite underlying pixel */
558 yuv_to_rgb( &r, &g, &b,
559 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
561 p32_dst[i_x] = (r<<i_rshift) |
568 uint32_t i_pix_dst = p32_dst[i_x];
569 yuv_to_rgb( &r, &g, &b,
570 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
572 p32_dst[i_x] = ( vlc_blend( r, (i_pix_dst & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
573 ( vlc_blend( g, (i_pix_dst & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
574 ( vlc_blend( b, (i_pix_dst & i_bmask)>>i_bshift, i_trans ) << i_bshift );
581 int i_rindex, i_gindex, i_bindex;
582 uint32_t i_rmask, i_gmask, i_bmask;
584 i_rmask = p_filter->fmt_out.video.i_rmask;
585 i_gmask = p_filter->fmt_out.video.i_gmask;
586 i_bmask = p_filter->fmt_out.video.i_bmask;
588 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
590 /* Draw until we reach the bottom of the subtitle */
591 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
592 p_dst += i_dst_pitch,
593 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
594 p_src_v += i_src_pitch )
596 /* Draw until we reach the end of the line */
597 for( i_x = 0; i_x < i_width; i_x++ )
600 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
605 yuv_to_rgb( &r, &g, &b,
606 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
608 vlc_blend_packed( &p_dst[ i_x * i_pix_pitch],
609 i_rindex, i_gindex, i_bindex,
610 r, g, b, i_alpha, true );
616 static void BlendYUVAYUVPacked( filter_t *p_filter,
617 picture_t *p_dst_pic, const picture_t *p_src,
618 int i_x_offset, int i_y_offset,
619 int i_width, int i_height, int i_alpha )
621 int i_src_pitch, i_dst_pitch;
622 uint8_t *p_dst, *p_src_y;
623 uint8_t *p_src_u, *p_src_v;
625 int i_x, i_y, i_pix_pitch, i_trans = 0;
626 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
627 int i_l_offset, i_u_offset, i_v_offset;
629 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
630 p_filter->fmt_out.video.i_chroma );
633 i_dst_pitch = p_dst_pic->p->i_pitch;
634 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
635 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
636 p_dst_pic->p->i_pitch *
637 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
639 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
640 0, 0, &p_filter->fmt_in.video, 1 );
641 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
642 0, 0, &p_filter->fmt_in.video, 2 );
643 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
644 0, 0, &p_filter->fmt_in.video, 2 );
645 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
646 0, 0, &p_filter->fmt_in.video, 1 );
648 i_width &= ~1; /* Needs to be a multiple of 2 */
650 /* Draw until we reach the bottom of the subtitle */
651 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
652 p_dst += i_dst_pitch,
653 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
654 p_src_v += i_src_pitch )
656 /* Draw until we reach the end of the line */
657 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
659 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
668 /* FIXME what's with 0xaa ? */
669 if( p_trans[i_x+1] > 0xaa )
671 i_u = (p_src_u[i_x]+p_src_u[i_x+1])>>1;
672 i_v = (p_src_v[i_x]+p_src_v[i_x+1])>>1;
680 vlc_blend_packed( &p_dst[i_x * 2],
681 i_l_offset, i_u_offset, i_v_offset,
682 p_src_y[i_x], i_u, i_v, i_trans, true );
686 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src_y[i_x], p_dst[i_x * 2 + i_l_offset], i_trans );
691 /***********************************************************************
693 ***********************************************************************/
694 static void BlendI420I420( filter_t *p_filter,
695 picture_t *p_dst, const picture_t *p_src,
696 int i_x_offset, int i_y_offset,
697 int i_width, int i_height, int i_alpha )
699 int i_src_pitch, i_dst_pitch;
700 uint8_t *p_src_y, *p_dst_y;
701 uint8_t *p_src_u, *p_dst_u;
702 uint8_t *p_src_v, *p_dst_v;
704 bool b_even_scanline = i_y_offset % 2;
706 if( i_alpha == 0xff )
708 BlendI420I420_no_alpha( p_filter, p_dst, p_src,
709 i_x_offset, i_y_offset, i_width, i_height );
714 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
715 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
716 p_filter->fmt_out.video.i_x_offset +
717 p_dst->p[Y_PLANE].i_pitch *
718 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
719 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
720 p_filter->fmt_out.video.i_x_offset/2 +
721 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
722 p_dst->p[U_PLANE].i_pitch;
723 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
724 p_filter->fmt_out.video.i_x_offset/2 +
725 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
726 p_dst->p[V_PLANE].i_pitch;
728 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
729 0, 0, &p_filter->fmt_in.video, 1 );
730 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
731 0, 0, &p_filter->fmt_in.video, 2 );
732 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
733 0, 0, &p_filter->fmt_in.video, 2 );
736 /* Draw until we reach the bottom of the subtitle */
737 for( i_y = 0; i_y < i_height; i_y++,
738 p_dst_y += i_dst_pitch,
739 p_src_y += i_src_pitch )
741 if( b_even_scanline )
743 p_dst_u += i_dst_pitch/2;
744 p_dst_v += i_dst_pitch/2;
746 b_even_scanline = !b_even_scanline;
748 /* Draw until we reach the end of the line */
749 for( i_x = 0; i_x < i_width; i_x++ )
755 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_alpha );
756 if( b_even_scanline && i_x % 2 == 0 )
758 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x/2], p_dst_u[i_x/2], i_alpha );
759 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x/2], p_dst_v[i_x/2], i_alpha );
764 p_src_u += i_src_pitch/2;
765 p_src_v += i_src_pitch/2;
769 static void BlendI420I420_no_alpha( filter_t *p_filter,
770 picture_t *p_dst, const picture_t *p_src,
771 int i_x_offset, int i_y_offset,
772 int i_width, int i_height )
774 int i_src_pitch, i_dst_pitch;
775 uint8_t *p_src_y, *p_dst_y;
776 uint8_t *p_src_u, *p_dst_u;
777 uint8_t *p_src_v, *p_dst_v;
779 bool b_even_scanline = i_y_offset % 2;
781 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
782 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
783 p_filter->fmt_out.video.i_x_offset +
784 p_dst->p[Y_PLANE].i_pitch *
785 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
786 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
787 p_filter->fmt_out.video.i_x_offset/2 +
788 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
789 p_dst->p[U_PLANE].i_pitch;
790 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
791 p_filter->fmt_out.video.i_x_offset/2 +
792 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
793 p_dst->p[V_PLANE].i_pitch;
795 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
796 0, 0, &p_filter->fmt_in.video, 1 );
797 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
798 0, 0, &p_filter->fmt_in.video, 2 );
799 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
800 0, 0, &p_filter->fmt_in.video, 2 );
804 /* Draw until we reach the bottom of the subtitle */
805 for( i_y = 0; i_y < i_height;
806 i_y++, p_dst_y += i_dst_pitch, p_src_y += i_src_pitch )
808 /* Completely opaque. Completely overwrite underlying pixel */
809 vlc_memcpy( p_dst_y, p_src_y, i_width );
810 if( b_even_scanline )
812 p_dst_u += i_dst_pitch/2;
813 p_dst_v += i_dst_pitch/2;
817 vlc_memcpy( p_dst_u, p_src_u, i_width/2 );
818 vlc_memcpy( p_dst_v, p_src_v, i_width/2 );
820 b_even_scanline = !b_even_scanline;
823 p_src_u += i_src_pitch/2;
824 p_src_v += i_src_pitch/2;
829 static void BlendI420R16( filter_t *p_filter,
830 picture_t *p_dst_pic, const picture_t *p_src,
831 int i_x_offset, int i_y_offset,
832 int i_width, int i_height, int i_alpha )
834 int i_src_pitch, i_dst_pitch;
835 uint8_t *p_dst, *p_src_y;
836 uint8_t *p_src_u, *p_src_v;
837 int i_x, i_y, i_pix_pitch;
840 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
841 i_dst_pitch = p_dst_pic->p->i_pitch;
842 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
843 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
844 p_dst_pic->p->i_pitch *
845 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
847 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
848 0, 0, &p_filter->fmt_in.video, 1 );
849 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
850 0, 0, &p_filter->fmt_in.video, 2 );
851 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
852 0, 0, &p_filter->fmt_in.video, 2 );
854 /* Draw until we reach the bottom of the subtitle */
855 for( i_y = 0; i_y < i_height; i_y++,
856 p_dst += i_dst_pitch,
857 p_src_y += i_src_pitch )
859 /* Draw until we reach the end of the line */
860 for( i_x = 0; i_x < i_width; i_x++ )
863 yuv_to_rgb( &r, &g, &b,
864 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
866 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
867 r, g, b, i_alpha, &p_filter->fmt_out.video );
871 p_src_u += i_src_pitch/2;
872 p_src_v += i_src_pitch/2;
877 static void BlendI420R24( filter_t *p_filter,
878 picture_t *p_dst_pic, const picture_t *p_src,
879 int i_x_offset, int i_y_offset,
880 int i_width, int i_height, int i_alpha )
882 int i_src_pitch, i_dst_pitch;
883 uint8_t *p_dst, *p_src_y;
884 uint8_t *p_src_u, *p_src_v;
885 int i_x, i_y, i_pix_pitch;
886 int i_rindex, i_gindex, i_bindex;
889 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
890 i_dst_pitch = p_dst_pic->p->i_pitch;
891 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
892 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
893 p_dst_pic->p->i_pitch *
894 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
896 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
897 0, 0, &p_filter->fmt_in.video, 1 );
898 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
899 0, 0, &p_filter->fmt_in.video, 2 );
900 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
901 0, 0, &p_filter->fmt_in.video, 2 );
903 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
905 /* Draw until we reach the bottom of the subtitle */
906 for( i_y = 0; i_y < i_height; i_y++,
907 p_dst += i_dst_pitch,
908 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
909 p_src_v += i_src_pitch )
911 /* Draw until we reach the end of the line */
912 for( i_x = 0; i_x < i_width; i_x++ )
918 yuv_to_rgb( &r, &g, &b,
919 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
921 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
922 i_rindex, i_gindex, i_bindex, r, g, b, i_alpha, true );
926 p_src_u += i_src_pitch/2;
927 p_src_v += i_src_pitch/2;
932 static void BlendI420YUVPacked( filter_t *p_filter,
933 picture_t *p_dst_pic, const picture_t *p_src,
934 int i_x_offset, int i_y_offset,
935 int i_width, int i_height, int i_alpha )
937 int i_src_pitch, i_dst_pitch;
938 uint8_t *p_dst, *p_src_y;
939 uint8_t *p_src_u, *p_src_v;
940 int i_x, i_y, i_pix_pitch;
941 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
942 int i_l_offset, i_u_offset, i_v_offset;
944 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
945 p_filter->fmt_out.video.i_chroma );
948 i_dst_pitch = p_dst_pic->p->i_pitch;
949 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
950 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
951 p_dst_pic->p->i_pitch *
952 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
954 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
955 0, 0, &p_filter->fmt_in.video, 1 );
956 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
957 0, 0, &p_filter->fmt_in.video, 2 );
958 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
959 0, 0, &p_filter->fmt_in.video, 2 );
961 i_width &= ~1; /* Needs to be a multiple of 2 */
963 /* Draw until we reach the bottom of the subtitle */
964 for( i_y = 0; i_y < i_height; i_y++,
965 p_dst += i_dst_pitch,
966 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
967 p_src_v += i_src_pitch )
969 /* Draw until we reach the end of the line */
970 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
976 vlc_blend_packed( &p_dst[i_x * 2],
977 i_l_offset, i_u_offset, i_v_offset,
978 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2], i_alpha, b_even );
982 p_src_u += i_src_pitch/2;
983 p_src_v += i_src_pitch/2;
988 /***********************************************************************
990 ***********************************************************************/
991 static void BlendPalI420( filter_t *p_filter,
992 picture_t *p_dst, const picture_t *p_src_pic,
993 int i_x_offset, int i_y_offset,
994 int i_width, int i_height, int i_alpha )
996 int i_src_pitch, i_dst_pitch;
997 uint8_t *p_src, *p_dst_y;
1000 int i_x, i_y, i_trans;
1001 bool b_even_scanline = i_y_offset % 2;
1003 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1004 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1005 p_filter->fmt_out.video.i_x_offset +
1006 p_dst->p[Y_PLANE].i_pitch *
1007 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1008 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1009 p_filter->fmt_out.video.i_x_offset/2 +
1010 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1011 p_dst->p[U_PLANE].i_pitch;
1012 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1013 p_filter->fmt_out.video.i_x_offset/2 +
1014 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1015 p_dst->p[V_PLANE].i_pitch;
1017 i_src_pitch = p_src_pic->p->i_pitch;
1018 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1019 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1021 #define p_pal p_filter->fmt_in.video.p_palette->palette
1023 /* Draw until we reach the bottom of the subtitle */
1024 for( i_y = 0; i_y < i_height; i_y++,
1025 p_dst_y += i_dst_pitch,
1026 p_src += i_src_pitch,
1027 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1028 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0 )
1030 const uint8_t *p_trans = p_src;
1031 b_even_scanline = !b_even_scanline;
1033 /* Draw until we reach the end of the line */
1034 for( i_x = 0; i_x < i_width; i_x++ )
1036 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1041 p_dst_y[i_x] = vlc_blend( p_pal[p_src[i_x]][0], p_dst_y[i_x], i_trans );
1042 if( b_even_scanline && ((i_x % 2) == 0) )
1044 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src[i_x]][1], p_dst_u[i_x/2], i_trans );
1045 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src[i_x]][2], p_dst_v[i_x/2], i_trans );
1052 static void BlendPalYUVPacked( filter_t *p_filter,
1053 picture_t *p_dst_pic, const picture_t *p_src_pic,
1054 int i_x_offset, int i_y_offset,
1055 int i_width, int i_height, int i_alpha )
1057 int i_src_pitch, i_dst_pitch;
1058 uint8_t *p_src, *p_dst;
1059 int i_x, i_y, i_pix_pitch, i_trans;
1060 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1061 int i_l_offset, i_u_offset, i_v_offset;
1063 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1064 p_filter->fmt_out.video.i_chroma );
1067 i_dst_pitch = p_dst_pic->p->i_pitch;
1068 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1069 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1070 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1072 i_src_pitch = p_src_pic->p->i_pitch;
1073 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1074 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1076 i_width &= ~1; /* Needs to be a multiple of 2 */
1078 #define p_pal p_filter->fmt_in.video.p_palette->palette
1080 /* Draw until we reach the bottom of the subtitle */
1081 for( i_y = 0; i_y < i_height; i_y++,
1082 p_dst += i_dst_pitch, p_src += i_src_pitch )
1084 const uint8_t *p_trans = p_src;
1085 /* Draw until we reach the end of the line */
1086 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1088 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1097 if( p_trans[i_x+1] > 0xaa )
1099 i_u = (p_pal[p_src[i_x]][1] + p_pal[p_src[i_x+1]][1]) >> 1;
1100 i_v = (p_pal[p_src[i_x]][2] + p_pal[p_src[i_x+1]][2]) >> 1;
1104 i_u = p_pal[p_src[i_x]][1];
1105 i_v = p_pal[p_src[i_x]][2];
1108 vlc_blend_packed( &p_dst[i_x * 2],
1109 i_l_offset, i_u_offset, i_v_offset,
1110 p_pal[p_src[i_x]][0], i_u, i_v, i_trans, true );
1114 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_pal[p_src[i_x]][0], p_dst[i_x * 2 + i_l_offset], i_trans );
1121 static void BlendPalRV( filter_t *p_filter,
1122 picture_t *p_dst_pic, const picture_t *p_src_pic,
1123 int i_x_offset, int i_y_offset,
1124 int i_width, int i_height, int i_alpha )
1126 int i_src_pitch, i_dst_pitch;
1127 uint8_t *p_src, *p_dst;
1128 int i_x, i_y, i_pix_pitch, i_trans;
1129 video_palette_t rgbpalette;
1130 int i_rindex, i_gindex, i_bindex;
1132 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1133 i_dst_pitch = p_dst_pic->p->i_pitch;
1134 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1135 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1136 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1138 i_src_pitch = p_src_pic->p->i_pitch;
1139 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1140 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1142 #define p_pal p_filter->fmt_in.video.p_palette->palette
1143 #define rgbpal rgbpalette.palette
1145 /* Convert palette first */
1146 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && i_y < 256; i_y++ )
1150 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1157 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1159 /* Draw until we reach the bottom of the subtitle */
1160 for( i_y = 0; i_y < i_height; i_y++,
1161 p_dst += i_dst_pitch, p_src += i_src_pitch )
1163 const uint8_t *p_trans = p_src;
1164 /* Draw until we reach the end of the line */
1165 for( i_x = 0; i_x < i_width; i_x++ )
1167 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1172 if( p_filter->fmt_out.video.i_chroma == VLC_CODEC_RGB15 || p_filter->fmt_out.video.i_chroma == VLC_CODEC_RGB16 )
1173 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1174 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1176 &p_filter->fmt_out.video );
1178 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1179 i_rindex, i_gindex, i_bindex,
1180 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1189 /***********************************************************************
1191 ***********************************************************************/
1192 static void BlendRGBAI420( filter_t *p_filter,
1193 picture_t *p_dst, const picture_t *p_src_pic,
1194 int i_x_offset, int i_y_offset,
1195 int i_width, int i_height, int i_alpha )
1197 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1202 int i_x, i_y, i_trans;
1205 bool b_even_scanline = i_y_offset % 2;
1207 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1208 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1209 p_filter->fmt_out.video.i_x_offset +
1210 p_dst->p[Y_PLANE].i_pitch *
1211 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1212 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1213 p_filter->fmt_out.video.i_x_offset/2 +
1214 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1215 p_dst->p[U_PLANE].i_pitch;
1216 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1217 p_filter->fmt_out.video.i_x_offset/2 +
1218 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1219 p_dst->p[V_PLANE].i_pitch;
1221 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1222 i_src_pitch = p_src_pic->p->i_pitch;
1223 p_src = p_src_pic->p->p_pixels +
1224 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1225 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1228 /* Draw until we reach the bottom of the subtitle */
1229 for( i_y = 0; i_y < i_height; i_y++,
1230 p_dst_y += i_dst_pitch,
1231 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1232 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1233 p_src += i_src_pitch )
1235 b_even_scanline = !b_even_scanline;
1237 /* Draw until we reach the end of the line */
1238 for( i_x = 0; i_x < i_width; i_x++ )
1240 const int R = p_src[i_x * i_src_pix_pitch + 0];
1241 const int G = p_src[i_x * i_src_pix_pitch + 1];
1242 const int B = p_src[i_x * i_src_pix_pitch + 2];
1244 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1249 rgb_to_yuv( &y, &u, &v, R, G, B );
1251 p_dst_y[i_x] = vlc_blend( y, p_dst_y[i_x], i_trans );
1252 if( b_even_scanline && i_x % 2 == 0 )
1254 p_dst_u[i_x/2] = vlc_blend( u, p_dst_u[i_x/2], i_trans );
1255 p_dst_v[i_x/2] = vlc_blend( v, p_dst_v[i_x/2], i_trans );
1261 static void BlendRGBAR24( filter_t *p_filter,
1262 picture_t *p_dst_pic, const picture_t *p_src_pic,
1263 int i_x_offset, int i_y_offset,
1264 int i_width, int i_height, int i_alpha )
1266 int i_src_pitch, i_dst_pitch;
1267 uint8_t *p_dst, *p_src;
1268 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1269 int i_rindex, i_gindex, i_bindex;
1271 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1272 i_dst_pitch = p_dst_pic->p->i_pitch;
1273 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1274 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1275 p_dst_pic->p->i_pitch *
1276 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1278 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1279 i_src_pitch = p_src_pic->p->i_pitch;
1280 p_src = p_src_pic->p->p_pixels +
1281 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1282 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1284 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1286 /* Draw until we reach the bottom of the subtitle */
1287 for( i_y = 0; i_y < i_height; i_y++,
1288 p_dst += i_dst_pitch, p_src += i_src_pitch )
1290 /* Draw until we reach the end of the line */
1291 for( i_x = 0; i_x < i_width; i_x++ )
1293 const int R = p_src[i_x * i_src_pix_pitch + 0];
1294 const int G = p_src[i_x * i_src_pix_pitch + 1];
1295 const int B = p_src[i_x * i_src_pix_pitch + 2];
1297 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1302 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1303 i_rindex, i_gindex, i_bindex,
1304 R, G, B, i_trans, true );
1309 static void BlendRGBAR16( filter_t *p_filter,
1310 picture_t *p_dst_pic, const picture_t *p_src_pic,
1311 int i_x_offset, int i_y_offset,
1312 int i_width, int i_height, int i_alpha )
1314 int i_src_pitch, i_dst_pitch;
1315 uint8_t *p_dst, *p_src;
1316 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1318 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1319 i_dst_pitch = p_dst_pic->p->i_pitch;
1320 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1321 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1322 p_dst_pic->p->i_pitch *
1323 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1325 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1326 i_src_pitch = p_src_pic->p->i_pitch;
1327 p_src = p_src_pic->p->p_pixels +
1328 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1329 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1331 /* Draw until we reach the bottom of the subtitle */
1332 for( i_y = 0; i_y < i_height; i_y++,
1333 p_dst += i_dst_pitch, p_src += i_src_pitch )
1335 /* Draw until we reach the end of the line */
1336 for( i_x = 0; i_x < i_width; i_x++ )
1338 const int R = p_src[i_x * i_src_pix_pitch + 0];
1339 const int G = p_src[i_x * i_src_pix_pitch + 1];
1340 const int B = p_src[i_x * i_src_pix_pitch + 2];
1342 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1347 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1348 R, G, B, i_trans, &p_filter->fmt_out.video );
1353 static void BlendRGBAYUVPacked( filter_t *p_filter,
1354 picture_t *p_dst_pic, const picture_t *p_src_pic,
1355 int i_x_offset, int i_y_offset,
1356 int i_width, int i_height, int i_alpha )
1358 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1359 uint8_t *p_dst, *p_src;
1360 int i_x, i_y, i_pix_pitch, i_trans;
1361 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1362 int i_l_offset, i_u_offset, i_v_offset;
1365 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1366 p_filter->fmt_out.video.i_chroma );
1369 i_dst_pitch = p_dst_pic->p->i_pitch;
1370 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1371 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1372 p_dst_pic->p->i_pitch *
1373 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1375 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1376 i_src_pitch = p_src_pic->p->i_pitch;
1377 p_src = p_src_pic->p->p_pixels +
1378 p_filter->fmt_in.video.i_x_offset * i_src_pitch +
1379 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1381 i_width &= ~1; /* Needs to be a multiple of 2 */
1383 /* Draw until we reach the bottom of the subtitle */
1384 for( i_y = 0; i_y < i_height; i_y++,
1385 p_dst += i_dst_pitch,
1386 p_src += i_src_pitch )
1388 /* Draw until we reach the end of the line */
1389 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1391 const int R = p_src[i_x * i_src_pix_pitch + 0];
1392 const int G = p_src[i_x * i_src_pix_pitch + 1];
1393 const int B = p_src[i_x * i_src_pix_pitch + 2];
1395 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1400 rgb_to_yuv( &y, &u, &v, R, G, B );
1402 vlc_blend_packed( &p_dst[i_x * 2],
1403 i_l_offset, i_u_offset, i_v_offset,
1404 y, u, v, i_trans, b_even );