1 /*****************************************************************************
2 * blend.c: alpha blend 2 pictures together
3 *****************************************************************************
4 * Copyright (C) 2003-2008 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>
36 #include "vlc_filter.h"
38 /*****************************************************************************
40 *****************************************************************************/
41 static int OpenFilter ( vlc_object_t * );
42 static void CloseFilter( vlc_object_t * );
45 set_description( N_("Video pictures blending") );
46 set_capability( "video blending", 100 );
47 set_callbacks( OpenFilter, CloseFilter );
51 /*****************************************************************************
52 * filter_sys_t : filter descriptor
53 *****************************************************************************/
59 #define FCC_YUVA VLC_FOURCC('Y','U','V','A')
60 #define FCC_YUVP VLC_FOURCC('Y','U','V','P')
61 #define FCC_RGBA VLC_FOURCC('R','G','B','A')
63 #define FCC_I420 VLC_FOURCC('I','4','2','0')
64 #define FCC_YV12 VLC_FOURCC('Y','V','1','2')
65 #define FCC_YUY2 VLC_FOURCC('Y','U','Y','2')
66 #define FCC_UYVY VLC_FOURCC('U','Y','V','Y')
67 #define FCC_YVYU VLC_FOURCC('Y','V','Y','U')
68 #define FCC_RV15 VLC_FOURCC('R','V','1','5')
69 #define FCC_RV16 VLC_FOURCC('R','V','1','6')
70 #define FCC_RV24 VLC_FOURCC('R','V','2','4')
71 #define FCC_RV32 VLC_FOURCC('R','V','3','2')
73 /****************************************************************************
75 ****************************************************************************/
76 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
80 static void BlendYUVAI420( filter_t *, picture_t *, picture_t *, picture_t *,
81 int, int, int, int, int );
82 static void BlendYUVARV16( filter_t *, picture_t *, picture_t *, picture_t *,
83 int, int, int, int, int );
84 static void BlendYUVARV24( filter_t *, picture_t *, picture_t *, picture_t *,
85 int, int, int, int, int );
86 static void BlendYUVAYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
87 int, int, int, int, int );
90 static void BlendI420I420( filter_t *, picture_t *, picture_t *, picture_t *,
91 int, int, int, int, int );
92 static void BlendI420I420_no_alpha(
93 filter_t *, picture_t *, picture_t *, picture_t *,
95 static void BlendI420R16( filter_t *, picture_t *, picture_t *, picture_t *,
96 int, int, int, int, int );
97 static void BlendI420R24( filter_t *, picture_t *, picture_t *, picture_t *,
98 int, int, int, int, int );
99 static void BlendI420YUVPacked( filter_t *, picture_t *, picture_t *,
100 picture_t *, int, int, int, int, int );
103 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
104 int, int, int, int, int );
105 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
106 int, int, int, int, int );
107 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
108 int, int, int, int, int );
111 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
112 int, int, int, int, int );
113 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
114 picture_t *, int, int, int, int, int );
115 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
116 int, int, int, int, int );
117 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
118 int, int, int, int, int );
120 static void video_format_FixRgb( video_format_t *p_fmt );
122 /*****************************************************************************
123 * OpenFilter: probe the filter and return score
124 *****************************************************************************/
125 static int OpenFilter( vlc_object_t *p_this )
127 filter_t *p_filter = (filter_t*)p_this;
130 /* Check if we can handle that format.
131 * We could try to use a chroma filter if we can't. */
132 int in_chroma = p_filter->fmt_in.video.i_chroma;
133 int out_chroma = p_filter->fmt_out.video.i_chroma;
134 if( ( in_chroma != FCC_YUVA && in_chroma != FCC_I420 &&
135 in_chroma != FCC_YV12 && in_chroma != FCC_YUVP &&
136 in_chroma != FCC_RGBA ) ||
137 ( out_chroma != FCC_I420 && out_chroma != FCC_YUY2 &&
138 out_chroma != FCC_YV12 && out_chroma != FCC_UYVY &&
139 out_chroma != FCC_YVYU && out_chroma != FCC_RV15 &&
140 out_chroma != FCC_YVYU && out_chroma != FCC_RV16 &&
141 out_chroma != FCC_RV24 && out_chroma != FCC_RV32 ) )
146 /* Allocate the memory needed to store the decoder's structure */
147 p_filter->p_sys = p_sys = malloc(sizeof(filter_sys_t));
152 p_filter->pf_video_blend = Blend;
154 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
155 (char *)&p_filter->fmt_in.video.i_chroma,
156 (char *)&p_filter->fmt_out.video.i_chroma );
161 /*****************************************************************************
162 * CloseFilter: clean up the filter
163 *****************************************************************************/
164 static void CloseFilter( vlc_object_t *p_this )
166 filter_t *p_filter = (filter_t*)p_this;
167 filter_sys_t *p_sys = p_filter->p_sys;
172 /****************************************************************************
173 * Blend: the whole thing
174 ****************************************************************************
175 * This function is called just after the thread is launched.
176 ****************************************************************************/
177 typedef void (*BlendFunction)( filter_t *, picture_t *,
178 picture_t *, picture_t *,
179 int , int , int , int , int );
181 #define FCC_PLANAR_420 { FCC_I420, FCC_YV12, 0 }
182 #define FCC_PACKED_422 { FCC_YUY2, FCC_UYVY, FCC_YVYU, 0 }
183 #define FCC_RGB_16 { FCC_RV15, FCC_RV16, 0 }
184 #define FCC_RGB_24 { FCC_RV24, FCC_RV32, 0 }
186 #define BLEND_CFG( fccSrc, fctPlanar, fctPacked, fctRgb16, fctRgb24 ) \
187 { .src = fccSrc, .p_dst = FCC_PLANAR_420, .pf_blend = fctPlanar }, \
188 { .src = fccSrc, .p_dst = FCC_PACKED_422, .pf_blend = fctPacked }, \
189 { .src = fccSrc, .p_dst = FCC_RGB_16, .pf_blend = fctRgb16 }, \
190 { .src = fccSrc, .p_dst = FCC_RGB_24, .pf_blend = fctRgb24 }
195 vlc_fourcc_t p_dst[16];
196 BlendFunction pf_blend;
199 BLEND_CFG( FCC_YUVA, BlendYUVAI420, BlendYUVAYUVPacked, BlendYUVARV16, BlendYUVARV24 ),
201 BLEND_CFG( FCC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ),
203 BLEND_CFG( FCC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ),
205 BLEND_CFG( FCC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
207 BLEND_CFG( FCC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
212 static void Blend( filter_t *p_filter, picture_t *p_dst,
213 picture_t *p_dst_orig, picture_t *p_src,
214 int i_x_offset, int i_y_offset, int i_alpha )
216 int i_width, i_height;
221 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
222 (int)p_filter->fmt_in.video.i_visible_width);
224 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
225 (int)p_filter->fmt_in.video.i_visible_height);
227 if( i_width <= 0 || i_height <= 0 )
230 video_format_FixRgb( &p_filter->fmt_out.video );
231 video_format_FixRgb( &p_filter->fmt_in.video );
234 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
235 (char *)&p_filter->fmt_in.video.i_chroma,
236 (char *)&p_filter->fmt_out.video.i_chroma );
239 for( int i = 0; p_blend_cfg[i].src != 0; i++ )
241 if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma )
243 for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ )
245 if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma )
248 p_blend_cfg[i].pf_blend( p_filter, p_dst, p_dst_orig, p_src,
249 i_x_offset, i_y_offset, i_width, i_height, i_alpha );
254 msg_Dbg( p_filter, "no matching alpha blending routine "
255 "(chroma: %4.4s -> %4.4s)",
256 (char *)&p_filter->fmt_in.video.i_chroma,
257 (char *)&p_filter->fmt_out.video.i_chroma );
260 /***********************************************************************
262 ***********************************************************************/
263 static inline uint8_t vlc_uint8( int v )
272 #define MAX_TRANS 255
275 static inline int vlc_blend( int v1, int v2, int a )
277 /* TODO bench if the tests really increase speed */
280 else if( a == MAX_TRANS )
282 return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
285 static inline int vlc_alpha( int t, int a )
289 return (t * a) / 255;
292 static inline void yuv_to_rgb( int *r, int *g, int *b,
293 uint8_t y1, uint8_t u1, uint8_t v1 )
295 /* macros used for YUV pixel conversions */
296 # define SCALEBITS 10
297 # define ONE_HALF (1 << (SCALEBITS - 1))
298 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
300 int y, cb, cr, r_add, g_add, b_add;
304 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
305 g_add = - FIX(0.34414*255.0/224.0) * cb
306 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
307 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
308 y = (y1 - 16) * FIX(255.0/219.0);
309 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
310 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
311 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
317 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
318 int r, int g, int b )
320 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
321 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
322 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
325 static uint8_t *vlc_plane_start( int *pi_pitch,
326 picture_t *p_picture,
328 int i_x_offset, int i_y_offset,
329 const video_format_t *p_fmt,
332 const int i_pitch = p_picture->p[i_plane].i_pitch;
333 uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
335 const int i_dx = ( i_x_offset + p_fmt->i_x_offset ) / r;
336 const int i_dy = ( i_y_offset + p_fmt->i_y_offset ) / r;
340 return &p_pixels[ i_dy * i_pitch + i_dx ];
343 static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma )
345 static const struct {
349 { FCC_YUY2, 0, 1, 3 },
350 { FCC_UYVY, 1, 0, 2 },
351 { FCC_YVYU, 0, 3, 1 },
356 for( i = 0; p_index[i].chroma != 0; i++ )
358 if( p_index[i].chroma == i_chroma )
361 *pi_y = p_index[i].y;
362 *pi_u = p_index[i].u;
363 *pi_v = p_index[i].v;
366 static void vlc_blend_packed( uint8_t *p_dst, const uint8_t *p_src,
367 int i_offset0, int i_offset1, int i_offset2,
368 int c0, int c1, int c2, int i_alpha,
371 p_dst[i_offset0] = vlc_blend( c0, p_src[i_offset0], i_alpha );
374 p_dst[i_offset1] = vlc_blend( c1, p_src[i_offset1], i_alpha );
375 p_dst[i_offset2] = vlc_blend( c2, p_src[i_offset2], i_alpha );
379 static void vlc_blend_rgb16( uint16_t *p_dst, const uint16_t *p_src,
380 int R, int G, int B, int i_alpha,
381 const video_format_t *p_fmt )
383 const int i_pix = *p_src;
384 const int r = ( i_pix & p_fmt->i_rmask ) >> p_fmt->i_lrshift;
385 const int g = ( i_pix & p_fmt->i_gmask ) >> p_fmt->i_lgshift;
386 const int b = ( i_pix & p_fmt->i_bmask ) >> p_fmt->i_lbshift;
388 *p_dst = ( vlc_blend( R >> p_fmt->i_rrshift, r, i_alpha ) << p_fmt->i_lrshift ) |
389 ( vlc_blend( G >> p_fmt->i_rgshift, g, i_alpha ) << p_fmt->i_lgshift ) |
390 ( vlc_blend( B >> p_fmt->i_rbshift, b, i_alpha ) << p_fmt->i_lbshift );
393 /*****************************************************************************
394 * BinaryLog: computes the base 2 log of a binary value
395 *****************************************************************************
396 * This functions is used by MaskToShift, to get a bit index from a binary
398 *****************************************************************************/
399 static int BinaryLog( uint32_t i )
403 if( i == 0 ) return -31337;
405 if( i & 0xffff0000 ) i_log += 16;
406 if( i & 0xff00ff00 ) i_log += 8;
407 if( i & 0xf0f0f0f0 ) i_log += 4;
408 if( i & 0xcccccccc ) i_log += 2;
409 if( i & 0xaaaaaaaa ) i_log += 1;
414 static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex,
415 const video_format_t *p_fmt )
417 if( p_fmt->i_chroma != FCC_RV24 && p_fmt->i_chroma != FCC_RV32 )
420 /* XXX it will works only if mask are 8 bits aligned */
421 #ifdef WORDS_BIGENDIAN
422 const int i_mask_bits = p_fmt->i_chroma == FCC_RV24 ? 24 : 32;
423 *pi_rindex = ( i_mask_bits - p_fmt->i_lrshift ) / 8;
424 *pi_gindex = ( i_mask_bits - p_fmt->i_lgshift ) / 8;
425 *pi_bindex = ( i_mask_bits - p_fmt->i_lbshift ) / 8;
427 *pi_rindex = p_fmt->i_lrshift / 8;
428 *pi_gindex = p_fmt->i_lgshift / 8;
429 *pi_bindex = p_fmt->i_lbshift / 8;
434 * It transforms a color mask into right and left shifts
435 * FIXME copied from video_output.c
437 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
439 uint32_t i_low, i_high; /* lower hand higher bits of the mask */
443 *pi_left = *pi_right = 0;
448 i_low = i_high = i_mask;
450 i_low &= - (int32_t)i_low; /* lower bit of the mask */
451 i_high += i_low; /* higher bit of the mask */
453 /* Transform bits into an index. Also deal with i_high overflow, which
454 * is faster than changing the BinaryLog code to handle 64 bit integers. */
455 i_low = BinaryLog (i_low);
456 i_high = i_high ? BinaryLog (i_high) : 32;
458 /* Update pointers and return */
460 *pi_right = (8 - i_high + i_low);
463 /* FIXME should be moved to src/ */
464 static void video_format_FixRgb( video_format_t *p_fmt )
466 if( p_fmt->i_chroma != FCC_RV15 &&
467 p_fmt->i_chroma != FCC_RV16 &&
468 p_fmt->i_chroma != FCC_RV24 &&
469 p_fmt->i_chroma != FCC_RV32 )
472 /* FIXME find right default mask */
473 if( !p_fmt->i_rmask || !p_fmt->i_gmask || !p_fmt->i_bmask )
475 switch( p_fmt->i_chroma )
478 p_fmt->i_rmask = 0x7c00;
479 p_fmt->i_gmask = 0x03e0;
480 p_fmt->i_bmask = 0x001f;
484 p_fmt->i_rmask = 0xf800;
485 p_fmt->i_gmask = 0x07e0;
486 p_fmt->i_bmask = 0x001f;
490 p_fmt->i_rmask = 0xff0000;
491 p_fmt->i_gmask = 0x00ff00;
492 p_fmt->i_bmask = 0x0000ff;
495 p_fmt->i_rmask = 0x00ff0000;
496 p_fmt->i_gmask = 0x0000ff00;
497 p_fmt->i_bmask = 0x000000ff;
506 MaskToShift( &p_fmt->i_lrshift, &p_fmt->i_rrshift,
508 MaskToShift( &p_fmt->i_lgshift, &p_fmt->i_rgshift,
510 MaskToShift( &p_fmt->i_lbshift, &p_fmt->i_rbshift,
514 /***********************************************************************
516 ***********************************************************************/
517 static void BlendYUVAI420( filter_t *p_filter, picture_t *p_dst,
518 picture_t *p_dst_orig, picture_t *p_src,
519 int i_x_offset, int i_y_offset,
520 int i_width, int i_height, int i_alpha )
522 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
523 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
524 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
525 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
527 int i_x, i_y, i_trans = 0;
528 bool b_even_scanline = i_y_offset % 2;
530 p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
531 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
532 p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
533 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
534 p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
535 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
537 p_src1_y = vlc_plane_start( &i_src1_pitch, p_dst_orig, Y_PLANE,
538 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
539 p_src1_u = vlc_plane_start( NULL, p_dst_orig, U_PLANE,
540 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
541 p_src1_v = vlc_plane_start( NULL, p_dst_orig, V_PLANE,
542 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
544 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
545 0, 0, &p_filter->fmt_in.video, 1 );
546 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
547 0, 0, &p_filter->fmt_in.video, 2 );
548 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
549 0, 0, &p_filter->fmt_in.video, 2 );
550 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
551 0, 0, &p_filter->fmt_in.video, 1 );
553 /* Draw until we reach the bottom of the subtitle */
554 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
555 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
556 p_src2_y += i_src2_pitch,
557 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
558 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
559 p_src2_u += i_src2_pitch,
560 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
561 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
562 p_src2_v += i_src2_pitch )
564 b_even_scanline = !b_even_scanline;
566 /* Draw until we reach the end of the line */
567 for( i_x = 0; i_x < i_width; i_x++ )
570 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
576 p_dst_y[i_x] = vlc_blend( p_src2_y[i_x], p_src1_y[i_x], i_trans );
577 if( b_even_scanline && i_x % 2 == 0 )
579 p_dst_u[i_x/2] = vlc_blend( p_src2_u[i_x], p_src1_u[i_x/2], i_trans );
580 p_dst_v[i_x/2] = vlc_blend( p_src2_v[i_x], p_src1_v[i_x/2], i_trans );
586 static void BlendYUVARV16( filter_t *p_filter, picture_t *p_dst_pic,
587 picture_t *p_dst_orig, picture_t *p_src,
588 int i_x_offset, int i_y_offset,
589 int i_width, int i_height, int i_alpha )
591 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
592 uint8_t *p_dst, *p_src1, *p_src2_y;
593 uint8_t *p_src2_u, *p_src2_v;
595 int i_x, i_y, i_pix_pitch, i_trans = 0;
598 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
599 i_dst_pitch = p_dst_pic->p->i_pitch;
600 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
601 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
602 p_dst_pic->p->i_pitch *
603 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
605 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
606 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
607 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
608 p_dst_orig->p->i_pitch *
609 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
611 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
612 0, 0, &p_filter->fmt_in.video, 1 );
613 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
614 0, 0, &p_filter->fmt_in.video, 2 );
615 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
616 0, 0, &p_filter->fmt_in.video, 2 );
617 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
618 0, 0, &p_filter->fmt_in.video, 1 );
620 /* Draw until we reach the bottom of the subtitle */
621 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
622 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
623 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
624 p_src2_v += i_src2_pitch )
626 /* Draw until we reach the end of the line */
627 for( i_x = 0; i_x < i_width; i_x++ )
630 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
635 yuv_to_rgb( &r, &g, &b,
636 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
638 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
639 (const uint16_t*)&p_src1[i_x * i_pix_pitch],
640 r, g, b, i_trans, &p_filter->fmt_out.video );
645 static void BlendYUVARV24( filter_t *p_filter, picture_t *p_dst_pic,
646 picture_t *p_dst_orig, picture_t *p_src,
647 int i_x_offset, int i_y_offset,
648 int i_width, int i_height, int i_alpha )
650 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
651 uint8_t *p_dst, *p_src1, *p_src2_y;
652 uint8_t *p_src2_u, *p_src2_v;
654 int i_x, i_y, i_pix_pitch, i_trans = 0;
657 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
658 i_dst_pitch = p_dst_pic->p->i_pitch;
659 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
660 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
661 p_dst_pic->p->i_pitch *
662 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
664 i_src1_pitch = p_dst_orig->p->i_pitch;
665 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
666 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
667 p_dst_orig->p->i_pitch *
668 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
670 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
671 0, 0, &p_filter->fmt_in.video, 1 );
672 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
673 0, 0, &p_filter->fmt_in.video, 2 );
674 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
675 0, 0, &p_filter->fmt_in.video, 2 );
676 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
677 0, 0, &p_filter->fmt_in.video, 1 );
679 if( (i_pix_pitch == 4)
680 && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
684 ** if picture pixels are 32 bits long and lines addresses are 32 bit
685 ** aligned, optimize rendering
687 uint32_t *p32_dst = (uint32_t *)p_dst;
688 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
689 uint32_t *p32_src1 = (uint32_t *)p_src1;
690 uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
692 int i_rshift, i_gshift, i_bshift;
693 uint32_t i_rmask, i_gmask, i_bmask;
695 i_rmask = p_filter->fmt_out.video.i_rmask;
696 i_gmask = p_filter->fmt_out.video.i_gmask;
697 i_bmask = p_filter->fmt_out.video.i_bmask;
698 i_rshift = p_filter->fmt_out.video.i_lrshift;
699 i_gshift = p_filter->fmt_out.video.i_lgshift;
700 i_bshift = p_filter->fmt_out.video.i_lbshift;
702 /* Draw until we reach the bottom of the subtitle */
703 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
704 p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
705 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
706 p_src2_v += i_src2_pitch )
708 /* Draw until we reach the end of the line */
709 for( i_x = 0; i_x < i_width; i_x++ )
712 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
716 if( i_trans == MAX_TRANS )
718 /* Completely opaque. Completely overwrite underlying pixel */
719 yuv_to_rgb( &r, &g, &b,
720 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
722 p32_dst[i_x] = (r<<i_rshift) |
729 uint32_t i_pix_src1 = p32_src1[i_x];
730 yuv_to_rgb( &r, &g, &b,
731 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
733 p32_dst[i_x] = ( vlc_blend( r, (i_pix_src1 & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
734 ( vlc_blend( g, (i_pix_src1 & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
735 ( vlc_blend( b, (i_pix_src1 & i_bmask)>>i_bshift, i_trans ) << i_bshift );
742 int i_rindex, i_gindex, i_bindex;
743 uint32_t i_rmask, i_gmask, i_bmask;
745 i_rmask = p_filter->fmt_out.video.i_rmask;
746 i_gmask = p_filter->fmt_out.video.i_gmask;
747 i_bmask = p_filter->fmt_out.video.i_bmask;
749 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
751 /* Draw until we reach the bottom of the subtitle */
752 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
753 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
754 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
755 p_src2_v += i_src2_pitch )
757 /* Draw until we reach the end of the line */
758 for( i_x = 0; i_x < i_width; i_x++ )
761 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
766 yuv_to_rgb( &r, &g, &b,
767 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
769 vlc_blend_packed( &p_dst[ i_x * i_pix_pitch],
770 &p_src1[i_x * i_pix_pitch],
771 i_rindex, i_gindex, i_bindex,
772 r, g, b, i_alpha, true );
778 static void BlendYUVAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
779 picture_t *p_dst_orig, picture_t *p_src,
780 int i_x_offset, int i_y_offset,
781 int i_width, int i_height, int i_alpha )
783 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
784 uint8_t *p_dst, *p_src1, *p_src2_y;
785 uint8_t *p_src2_u, *p_src2_v;
787 int i_x, i_y, i_pix_pitch, i_trans = 0;
788 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
789 int i_l_offset, i_u_offset, i_v_offset;
791 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
792 p_filter->fmt_out.video.i_chroma );
795 i_dst_pitch = p_dst_pic->p->i_pitch;
796 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
797 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
798 p_dst_pic->p->i_pitch *
799 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
801 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
802 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
803 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
804 p_dst_orig->p->i_pitch *
805 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
807 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
808 0, 0, &p_filter->fmt_in.video, 1 );
809 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
810 0, 0, &p_filter->fmt_in.video, 2 );
811 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
812 0, 0, &p_filter->fmt_in.video, 2 );
813 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
814 0, 0, &p_filter->fmt_in.video, 1 );
816 i_width &= ~1; /* Needs to be a multiple of 2 */
818 /* Draw until we reach the bottom of the subtitle */
819 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
820 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
821 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
822 p_src2_v += i_src2_pitch )
824 /* Draw until we reach the end of the line */
825 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
827 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
836 /* FIXME what's with 0xaa ? */
837 if( p_trans[i_x+1] > 0xaa )
839 i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
840 i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
848 vlc_blend_packed( &p_dst[i_x * 2], &p_src1[i_x * 2],
849 i_l_offset, i_u_offset, i_v_offset,
850 p_src2_y[i_x], i_u, i_v, i_trans, true );
854 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_trans );
859 /***********************************************************************
861 ***********************************************************************/
862 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
863 picture_t *p_dst_orig, picture_t *p_src,
864 int i_x_offset, int i_y_offset,
865 int i_width, int i_height, int i_alpha )
867 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
868 uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
869 uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
870 uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
872 bool b_even_scanline = i_y_offset % 2;
874 if( i_alpha == 0xff )
876 BlendI420I420_no_alpha( p_filter, p_dst, p_dst_orig, p_src,
877 i_x_offset, i_y_offset, i_width, i_height );
882 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
883 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
884 p_filter->fmt_out.video.i_x_offset +
885 p_dst->p[Y_PLANE].i_pitch *
886 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
887 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
888 p_filter->fmt_out.video.i_x_offset/2 +
889 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
890 p_dst->p[U_PLANE].i_pitch;
891 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
892 p_filter->fmt_out.video.i_x_offset/2 +
893 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
894 p_dst->p[V_PLANE].i_pitch;
896 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
897 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
898 p_filter->fmt_out.video.i_x_offset +
899 p_dst_orig->p[Y_PLANE].i_pitch *
900 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
901 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
902 p_filter->fmt_out.video.i_x_offset/2 +
903 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
904 p_dst_orig->p[U_PLANE].i_pitch;
905 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
906 p_filter->fmt_out.video.i_x_offset/2 +
907 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
908 p_dst_orig->p[V_PLANE].i_pitch;
910 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
911 0, 0, &p_filter->fmt_in.video, 1 );
912 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
913 0, 0, &p_filter->fmt_in.video, 2 );
914 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
915 0, 0, &p_filter->fmt_in.video, 2 );
918 /* Draw until we reach the bottom of the subtitle */
919 for( i_y = 0; i_y < i_height; i_y++,
920 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
921 p_src2_y += i_src2_pitch )
923 if( b_even_scanline )
925 p_dst_u += i_dst_pitch/2;
926 p_dst_v += i_dst_pitch/2;
927 p_src1_u += i_src1_pitch/2;
928 p_src1_v += i_src1_pitch/2;
930 b_even_scanline = !b_even_scanline;
932 /* Draw until we reach the end of the line */
933 for( i_x = 0; i_x < i_width; i_x++ )
939 p_dst_y[i_x] = vlc_blend( p_src2_y[i_x], p_src1_y[i_x], i_alpha );
940 if( b_even_scanline && i_x % 2 == 0 )
942 p_dst_u[i_x/2] = vlc_blend( p_src2_u[i_x/2], p_src1_u[i_x/2], i_alpha );
943 p_dst_v[i_x/2] = vlc_blend( p_src2_v[i_x/2], p_src1_v[i_x/2], i_alpha );
948 p_src2_u += i_src2_pitch/2;
949 p_src2_v += i_src2_pitch/2;
953 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
954 picture_t *p_dst_orig, picture_t *p_src,
955 int i_x_offset, int i_y_offset,
956 int i_width, int i_height )
958 int i_src2_pitch, i_dst_pitch;
959 uint8_t *p_src2_y, *p_dst_y;
960 uint8_t *p_src2_u, *p_dst_u;
961 uint8_t *p_src2_v, *p_dst_v;
963 bool b_even_scanline = i_y_offset % 2;
965 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
966 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
967 p_filter->fmt_out.video.i_x_offset +
968 p_dst->p[Y_PLANE].i_pitch *
969 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
970 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
971 p_filter->fmt_out.video.i_x_offset/2 +
972 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
973 p_dst->p[U_PLANE].i_pitch;
974 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
975 p_filter->fmt_out.video.i_x_offset/2 +
976 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
977 p_dst->p[V_PLANE].i_pitch;
979 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
980 0, 0, &p_filter->fmt_in.video, 1 );
981 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
982 0, 0, &p_filter->fmt_in.video, 2 );
983 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
984 0, 0, &p_filter->fmt_in.video, 2 );
988 /* Draw until we reach the bottom of the subtitle */
989 for( i_y = 0; i_y < i_height;
990 i_y++, p_dst_y += i_dst_pitch, p_src2_y += i_src2_pitch )
992 /* Completely opaque. Completely overwrite underlying pixel */
993 vlc_memcpy( p_dst_y, p_src2_y, i_width );
994 if( b_even_scanline )
996 p_dst_u += i_dst_pitch/2;
997 p_dst_v += i_dst_pitch/2;
1001 vlc_memcpy( p_dst_u, p_src2_u, i_width/2 );
1002 vlc_memcpy( p_dst_v, p_src2_v, i_width/2 );
1004 b_even_scanline = !b_even_scanline;
1007 p_src2_u += i_src2_pitch/2;
1008 p_src2_v += i_src2_pitch/2;
1013 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1014 picture_t *p_dst_orig, picture_t *p_src,
1015 int i_x_offset, int i_y_offset,
1016 int i_width, int i_height, int i_alpha )
1018 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1019 uint8_t *p_dst, *p_src1, *p_src2_y;
1020 uint8_t *p_src2_u, *p_src2_v;
1021 int i_x, i_y, i_pix_pitch;
1024 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1025 i_dst_pitch = p_dst_pic->p->i_pitch;
1026 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1027 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1028 p_dst_pic->p->i_pitch *
1029 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1031 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1032 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1033 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1034 p_dst_orig->p->i_pitch *
1035 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1037 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
1038 0, 0, &p_filter->fmt_in.video, 1 );
1039 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
1040 0, 0, &p_filter->fmt_in.video, 2 );
1041 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
1042 0, 0, &p_filter->fmt_in.video, 2 );
1044 /* Draw until we reach the bottom of the subtitle */
1045 for( i_y = 0; i_y < i_height; i_y++,
1046 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1047 p_src2_y += i_src2_pitch )
1049 /* Draw until we reach the end of the line */
1050 for( i_x = 0; i_x < i_width; i_x++ )
1053 yuv_to_rgb( &r, &g, &b,
1054 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1056 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1057 (const uint16_t*)&p_src1[i_x * i_pix_pitch],
1058 r, g, b, 0xff, &p_filter->fmt_out.video );
1062 p_src2_u += i_src2_pitch/2;
1063 p_src2_v += i_src2_pitch/2;
1068 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1069 picture_t *p_dst_orig, picture_t *p_src,
1070 int i_x_offset, int i_y_offset,
1071 int i_width, int i_height, int i_alpha )
1073 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1074 uint8_t *p_dst, *p_src1, *p_src2_y;
1075 uint8_t *p_src2_u, *p_src2_v;
1076 int i_x, i_y, i_pix_pitch;
1077 int i_rindex, i_gindex, i_bindex;
1080 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1081 i_dst_pitch = p_dst_pic->p->i_pitch;
1082 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1083 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1084 p_dst_pic->p->i_pitch *
1085 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1087 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1088 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1089 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1090 p_dst_orig->p->i_pitch *
1091 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1093 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
1094 0, 0, &p_filter->fmt_in.video, 1 );
1095 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
1096 0, 0, &p_filter->fmt_in.video, 2 );
1097 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
1098 0, 0, &p_filter->fmt_in.video, 2 );
1100 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1102 /* Draw until we reach the bottom of the subtitle */
1103 for( i_y = 0; i_y < i_height; i_y++,
1104 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1105 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1106 p_src2_v += i_src2_pitch )
1108 /* Draw until we reach the end of the line */
1109 for( i_x = 0; i_x < i_width; i_x++ )
1115 yuv_to_rgb( &r, &g, &b,
1116 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1118 vlc_blend_packed( &p_dst[i_x * i_pix_pitch], &p_src1[i_x * i_pix_pitch],
1119 i_rindex, i_gindex, i_bindex, r, g, b, i_alpha, true );
1123 p_src2_u += i_src2_pitch/2;
1124 p_src2_v += i_src2_pitch/2;
1129 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1130 picture_t *p_dst_orig, picture_t *p_src,
1131 int i_x_offset, int i_y_offset,
1132 int i_width, int i_height, int i_alpha )
1134 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1135 uint8_t *p_dst, *p_src1, *p_src2_y;
1136 uint8_t *p_src2_u, *p_src2_v;
1137 int i_x, i_y, i_pix_pitch;
1138 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1139 int i_l_offset, i_u_offset, i_v_offset;
1141 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1142 p_filter->fmt_out.video.i_chroma );
1145 i_dst_pitch = p_dst_pic->p->i_pitch;
1146 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1147 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1148 p_dst_pic->p->i_pitch *
1149 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1151 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1152 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1153 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1154 p_dst_orig->p->i_pitch *
1155 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1157 p_src2_y = vlc_plane_start( &i_src2_pitch, p_src, Y_PLANE,
1158 0, 0, &p_filter->fmt_in.video, 1 );
1159 p_src2_u = vlc_plane_start( NULL, p_src, U_PLANE,
1160 0, 0, &p_filter->fmt_in.video, 2 );
1161 p_src2_v = vlc_plane_start( NULL, p_src, V_PLANE,
1162 0, 0, &p_filter->fmt_in.video, 2 );
1164 i_width &= ~1; /* Needs to be a multiple of 2 */
1166 /* Draw until we reach the bottom of the subtitle */
1167 for( i_y = 0; i_y < i_height; i_y++,
1168 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1169 p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1170 p_src2_v += i_src2_pitch )
1172 /* Draw until we reach the end of the line */
1173 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1179 vlc_blend_packed( &p_dst[i_x * 2], &p_src1[i_x * 2],
1180 i_l_offset, i_u_offset, i_v_offset,
1181 p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2], i_alpha, b_even );
1185 p_src2_u += i_src2_pitch/2;
1186 p_src2_v += i_src2_pitch/2;
1191 /***********************************************************************
1193 ***********************************************************************/
1194 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1195 picture_t *p_dst_orig, picture_t *p_src,
1196 int i_x_offset, int i_y_offset,
1197 int i_width, int i_height, int i_alpha )
1199 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1200 uint8_t *p_src1_y, *p_src2, *p_dst_y;
1201 uint8_t *p_src1_u, *p_dst_u;
1202 uint8_t *p_src1_v, *p_dst_v;
1203 int i_x, i_y, i_trans;
1204 bool b_even_scanline = i_y_offset % 2;
1206 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1207 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1208 p_filter->fmt_out.video.i_x_offset +
1209 p_dst->p[Y_PLANE].i_pitch *
1210 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1211 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1212 p_filter->fmt_out.video.i_x_offset/2 +
1213 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1214 p_dst->p[U_PLANE].i_pitch;
1215 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1216 p_filter->fmt_out.video.i_x_offset/2 +
1217 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1218 p_dst->p[V_PLANE].i_pitch;
1220 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1221 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1222 p_filter->fmt_out.video.i_x_offset +
1223 p_dst_orig->p[Y_PLANE].i_pitch *
1224 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1225 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1226 p_filter->fmt_out.video.i_x_offset/2 +
1227 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1228 p_dst_orig->p[U_PLANE].i_pitch;
1229 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1230 p_filter->fmt_out.video.i_x_offset/2 +
1231 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1232 p_dst_orig->p[V_PLANE].i_pitch;
1234 i_src2_pitch = p_src->p->i_pitch;
1235 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1236 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1238 const uint8_t *p_trans = p_src2;
1239 #define p_pal p_filter->fmt_in.video.p_palette->palette
1241 /* Draw until we reach the bottom of the subtitle */
1242 for( i_y = 0; i_y < i_height; i_y++,
1243 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1244 p_src2 += i_src2_pitch,
1245 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1246 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1247 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1248 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1250 b_even_scanline = !b_even_scanline;
1252 /* Draw until we reach the end of the line */
1253 for( i_x = 0; i_x < i_width; i_x++ )
1255 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1260 p_dst_y[i_x] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1_y[i_x], i_trans );
1261 if( b_even_scanline && ((i_x % 2) == 0) )
1263 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src2[i_x]][1], p_src1_u[i_x/2], i_trans );
1264 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src2[i_x]][2], p_src1_v[i_x/2], i_trans );
1271 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1272 picture_t *p_dst_orig, picture_t *p_src,
1273 int i_x_offset, int i_y_offset,
1274 int i_width, int i_height, int i_alpha )
1276 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1277 uint8_t *p_src1, *p_src2, *p_dst;
1278 int i_x, i_y, i_pix_pitch, i_trans;
1279 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1280 int i_l_offset, i_u_offset, i_v_offset;
1282 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1283 p_filter->fmt_out.video.i_chroma );
1286 i_dst_pitch = p_dst_pic->p->i_pitch;
1287 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1288 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1289 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1291 i_src1_pitch = p_dst_orig->p->i_pitch;
1292 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1293 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1294 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1296 i_src2_pitch = p_src->p->i_pitch;
1297 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1298 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1300 i_width &= ~1; /* Needs to be a multiple of 2 */
1302 const uint8_t *p_trans = p_src2;
1303 #define p_pal p_filter->fmt_in.video.p_palette->palette
1305 /* Draw until we reach the bottom of the subtitle */
1306 for( i_y = 0; i_y < i_height; i_y++,
1307 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1309 /* Draw until we reach the end of the line */
1310 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1312 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1321 if( p_trans[i_x+1] > 0xaa )
1323 i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1324 i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1328 i_u = p_pal[p_src2[i_x]][1];
1329 i_v = p_pal[p_src2[i_x]][2];
1332 vlc_blend_packed( &p_dst[i_x * 2], &p_src1[i_x * 2],
1333 i_l_offset, i_u_offset, i_v_offset,
1334 p_pal[p_src2[i_x]][0], i_u, i_v, i_trans, true );
1338 p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1[i_x * 2 + i_l_offset], i_trans );
1345 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1346 picture_t *p_dst_orig, picture_t *p_src,
1347 int i_x_offset, int i_y_offset,
1348 int i_width, int i_height, int i_alpha )
1350 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1351 uint8_t *p_src1, *p_src2, *p_dst;
1352 int i_x, i_y, i_pix_pitch, i_trans;
1354 video_palette_t rgbpalette;
1355 int i_rindex, i_gindex, i_bindex;
1357 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1358 i_dst_pitch = p_dst_pic->p->i_pitch;
1359 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1360 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1361 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1363 i_src1_pitch = p_dst_orig->p->i_pitch;
1364 p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1365 p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1366 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1368 i_src2_pitch = p_src->p->i_pitch;
1369 p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1370 i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1372 const uint8_t *p_trans = p_src2;
1373 #define p_pal p_filter->fmt_in.video.p_palette->palette
1374 #define rgbpal rgbpalette.palette
1376 /* Convert palette first */
1377 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && i_y < 256; i_y++ )
1379 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1380 rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1384 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1386 /* Draw until we reach the bottom of the subtitle */
1387 for( i_y = 0; i_y < i_height; i_y++,
1388 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1390 /* Draw until we reach the end of the line */
1391 for( i_x = 0; i_x < i_width; i_x++ )
1393 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1398 if( p_filter->fmt_out.video.i_chroma == FCC_RV15 || p_filter->fmt_out.video.i_chroma == FCC_RV16 )
1399 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1400 (const uint16_t*)&p_src1[i_x * i_pix_pitch],
1401 rgbpal[p_src2[i_x]][0], rgbpal[p_src2[i_x]][1], rgbpal[p_src2[i_x]][3],
1403 &p_filter->fmt_out.video );
1405 vlc_blend_packed( &p_dst[i_x * i_pix_pitch], &p_src1[i_x * i_pix_pitch],
1406 i_rindex, i_gindex, i_bindex,
1407 rgbpal[p_src2[i_x]][0], rgbpal[p_src2[i_x]][1], rgbpal[p_src2[i_x]][3],
1416 /***********************************************************************
1418 ***********************************************************************/
1419 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1420 picture_t *p_dst_orig, picture_t *p_src,
1421 int i_x_offset, int i_y_offset,
1422 int i_width, int i_height, int i_alpha )
1424 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1425 uint8_t *p_src1_y, *p_dst_y;
1426 uint8_t *p_src1_u, *p_dst_u;
1427 uint8_t *p_src1_v, *p_dst_v;
1429 int i_x, i_y, i_trans;
1432 bool b_even_scanline = i_y_offset % 2;
1434 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1435 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1436 p_filter->fmt_out.video.i_x_offset +
1437 p_dst->p[Y_PLANE].i_pitch *
1438 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1439 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1440 p_filter->fmt_out.video.i_x_offset/2 +
1441 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1442 p_dst->p[U_PLANE].i_pitch;
1443 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1444 p_filter->fmt_out.video.i_x_offset/2 +
1445 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1446 p_dst->p[V_PLANE].i_pitch;
1448 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1449 p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1450 p_filter->fmt_out.video.i_x_offset +
1451 p_dst_orig->p[Y_PLANE].i_pitch *
1452 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1453 p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1454 p_filter->fmt_out.video.i_x_offset/2 +
1455 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1456 p_dst_orig->p[U_PLANE].i_pitch;
1457 p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1458 p_filter->fmt_out.video.i_x_offset/2 +
1459 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1460 p_dst_orig->p[V_PLANE].i_pitch;
1462 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1463 i_src2_pitch = p_src->p->i_pitch;
1464 p_src2 = p_src->p->p_pixels +
1465 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1466 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1469 /* Draw until we reach the bottom of the subtitle */
1470 for( i_y = 0; i_y < i_height; i_y++,
1471 p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1472 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1473 p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1474 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1475 p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1476 p_src2 += i_src2_pitch )
1478 b_even_scanline = !b_even_scanline;
1480 /* Draw until we reach the end of the line */
1481 for( i_x = 0; i_x < i_width; i_x++ )
1483 const int R = p_src2[i_x * i_src_pix_pitch + 0];
1484 const int G = p_src2[i_x * i_src_pix_pitch + 1];
1485 const int B = p_src2[i_x * i_src_pix_pitch + 2];
1487 i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1492 rgb_to_yuv( &y, &u, &v, R, G, B );
1494 p_dst_y[i_x] = vlc_blend( y, p_src1_y[i_x], i_trans );
1495 if( b_even_scanline && i_x % 2 == 0 )
1497 p_dst_u[i_x/2] = vlc_blend( u, p_src1_u[i_x/2], i_trans );
1498 p_dst_v[i_x/2] = vlc_blend( v, p_src1_v[i_x/2], i_trans );
1504 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1505 picture_t *p_dst_orig, picture_t *p_src,
1506 int i_x_offset, int i_y_offset,
1507 int i_width, int i_height, int i_alpha )
1509 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1510 uint8_t *p_dst, *p_src1, *p_src2;
1511 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1512 int i_rindex, i_gindex, i_bindex;
1514 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1515 i_dst_pitch = p_dst_pic->p->i_pitch;
1516 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1517 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1518 p_dst_pic->p->i_pitch *
1519 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1521 i_src1_pitch = p_dst_orig->p->i_pitch;
1522 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1523 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1524 p_dst_orig->p->i_pitch *
1525 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1527 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1528 i_src2_pitch = p_src->p->i_pitch;
1529 p_src2 = p_src->p->p_pixels +
1530 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1531 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1533 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1535 /* Draw until we reach the bottom of the subtitle */
1536 for( i_y = 0; i_y < i_height; i_y++,
1537 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1539 /* Draw until we reach the end of the line */
1540 for( i_x = 0; i_x < i_width; i_x++ )
1542 const int R = p_src2[i_x * i_src_pix_pitch + 0];
1543 const int G = p_src2[i_x * i_src_pix_pitch + 1];
1544 const int B = p_src2[i_x * i_src_pix_pitch + 2];
1546 i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1551 vlc_blend_packed( &p_dst[i_x * i_pix_pitch], &p_src1[i_x * i_pix_pitch],
1552 i_rindex, i_gindex, i_bindex,
1553 R, G, B, i_trans, true );
1558 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1559 picture_t *p_dst_orig, picture_t *p_src,
1560 int i_x_offset, int i_y_offset,
1561 int i_width, int i_height, int i_alpha )
1563 int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1564 uint8_t *p_dst, *p_src1, *p_src2;
1565 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1567 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1568 i_dst_pitch = p_dst_pic->p->i_pitch;
1569 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1570 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1571 p_dst_pic->p->i_pitch *
1572 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1574 i_src1_pitch = p_dst_orig->p->i_pitch;
1575 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1576 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1577 p_dst_orig->p->i_pitch *
1578 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1580 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1581 i_src2_pitch = p_src->p->i_pitch;
1582 p_src2 = p_src->p->p_pixels +
1583 p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1584 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1586 /* Draw until we reach the bottom of the subtitle */
1587 for( i_y = 0; i_y < i_height; i_y++,
1588 p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1590 /* Draw until we reach the end of the line */
1591 for( i_x = 0; i_x < i_width; i_x++ )
1593 const int R = p_src2[i_x * i_src_pix_pitch + 0];
1594 const int G = p_src2[i_x * i_src_pix_pitch + 1];
1595 const int B = p_src2[i_x * i_src_pix_pitch + 2];
1597 i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1602 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1603 (const uint16_t*)&p_src1[i_x * i_pix_pitch],
1604 R, G, B, i_trans, &p_filter->fmt_out.video );
1609 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1610 picture_t *p_dst_orig, picture_t *p_src,
1611 int i_x_offset, int i_y_offset,
1612 int i_width, int i_height, int i_alpha )
1614 int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1615 uint8_t *p_dst, *p_src1, *p_src2;
1617 int i_x, i_y, i_pix_pitch, i_trans;
1618 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1619 int i_l_offset, i_u_offset, i_v_offset;
1622 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1623 p_filter->fmt_out.video.i_chroma );
1626 i_dst_pitch = p_dst_pic->p->i_pitch;
1627 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1628 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1629 p_dst_pic->p->i_pitch *
1630 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1632 i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1633 p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1634 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1635 p_dst_orig->p->i_pitch *
1636 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1638 i_src_pix_pitch = p_src->p->i_pixel_pitch;
1639 i_src2_pitch = p_src->p->i_pitch;
1640 p_src2 = p_src->p->p_pixels +
1641 p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1642 p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1644 i_width &= ~1; /* Needs to be a multiple of 2 */
1646 /* Draw until we reach the bottom of the subtitle */
1647 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
1648 p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1649 p_src2 += i_src2_pitch )
1651 /* Draw until we reach the end of the line */
1652 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1654 const int R = p_src2[i_x * i_src_pix_pitch + 0];
1655 const int G = p_src2[i_x * i_src_pix_pitch + 1];
1656 const int B = p_src2[i_x * i_src_pix_pitch + 2];
1658 i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1663 rgb_to_yuv( &y, &u, &v, R, G, B );
1665 vlc_blend_packed( &p_dst[i_x * 2], &p_src1[i_x * 2],
1666 i_l_offset, i_u_offset, i_v_offset,
1667 y, u, v, i_trans, b_even );