Contrib: upnp/win32, remove strerror use, and other small hacks...
[vlc/asuraparaju-public.git] / modules / video_filter / blend.c
blob530be44c88b59c7371f1ee41cc819346a1a585a5
1 /*****************************************************************************
2 * blend.c: alpha blend 2 pictures together
3 *****************************************************************************
4 * Copyright (C) 2003-2009 the VideoLAN team
5 * $Id$
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 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <assert.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
37 /*****************************************************************************
38 * Module descriptor
39 *****************************************************************************/
40 static int OpenFilter ( vlc_object_t * );
41 static void CloseFilter( vlc_object_t * );
43 vlc_module_begin ()
44 set_description( N_("Video pictures blending") )
45 set_capability( "video blending", 100 )
46 set_callbacks( OpenFilter, CloseFilter )
47 vlc_module_end ()
49 /****************************************************************************
50 * Local prototypes
51 ****************************************************************************/
52 static void Blend( filter_t *, picture_t *, const picture_t *,
53 int, int, int );
55 /* YUVA */
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 );
65 /* I420, YV12 */
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 *,
70 int, int, int, int );
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 );
78 /* YUVP */
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 );
86 /* RGBA */
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 struct filter_sys_t
98 int i_blendcfg;
101 typedef void (*BlendFunction)( filter_t *,
102 picture_t *, const picture_t *,
103 int , int , int , int , int );
105 #define VLC_CODEC_PLANAR_420 { VLC_CODEC_I420, VLC_CODEC_J420, VLC_CODEC_YV12, 0 }
106 #define VLC_CODEC_PACKED_422 { VLC_CODEC_YUYV, VLC_CODEC_UYVY, VLC_CODEC_YVYU, VLC_CODEC_VYUY, 0 }
107 #define VLC_CODEC_RGB_16 { VLC_CODEC_RGB15, VLC_CODEC_RGB16, 0 }
108 #define VLC_CODEC_RGB_24 { VLC_CODEC_RGB24, VLC_CODEC_RGB32, 0 }
110 #define BLEND_CFG( fccSrc, fctPlanar, fctPacked, fctRgb16, fctRgb24 ) \
111 { .src = fccSrc, .p_dst = VLC_CODEC_PLANAR_420, .pf_blend = fctPlanar }, \
112 { .src = fccSrc, .p_dst = VLC_CODEC_PACKED_422, .pf_blend = fctPacked }, \
113 { .src = fccSrc, .p_dst = VLC_CODEC_RGB_16, .pf_blend = fctRgb16 }, \
114 { .src = fccSrc, .p_dst = VLC_CODEC_RGB_24, .pf_blend = fctRgb24 }
116 static const struct
118 vlc_fourcc_t src;
119 vlc_fourcc_t p_dst[16];
120 BlendFunction pf_blend;
121 } p_blend_cfg[] = {
123 BLEND_CFG( VLC_CODEC_YUVA, BlendYUVAI420, BlendYUVAYUVPacked, BlendYUVARV16, BlendYUVARV24 ),
125 BLEND_CFG( VLC_CODEC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ),
127 BLEND_CFG( VLC_CODEC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ),
129 BLEND_CFG( VLC_CODEC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
131 BLEND_CFG( VLC_CODEC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
133 { 0, {0,}, NULL }
136 /*****************************************************************************
137 * OpenFilter: probe the filter and return score
138 *****************************************************************************/
139 static int OpenFilter( vlc_object_t *p_this )
141 filter_t *p_filter = (filter_t*)p_this;
142 filter_sys_t *p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
143 if( !p_sys )
144 return VLC_ENOMEM;
145 p_filter->p_sys = p_sys;
146 p_filter->p_sys->i_blendcfg = -1;
148 /* Check if we can handle that format.
149 * We could try to use a chroma filter if we can't. */
150 int in_chroma = p_filter->fmt_in.video.i_chroma;
151 int out_chroma = p_filter->fmt_out.video.i_chroma;
153 if( ( in_chroma != VLC_CODEC_YUVA && in_chroma != VLC_CODEC_I420 &&
154 in_chroma != VLC_CODEC_YV12 && in_chroma != VLC_CODEC_YUVP &&
155 in_chroma != VLC_CODEC_RGBA ) ||
156 ( out_chroma != VLC_CODEC_I420 && out_chroma != VLC_CODEC_J420 &&
157 out_chroma != VLC_CODEC_YV12 &&
158 out_chroma != VLC_CODEC_YUYV && out_chroma != VLC_CODEC_YVYU &&
159 out_chroma != VLC_CODEC_UYVY && out_chroma != VLC_CODEC_VYUY &&
160 out_chroma != VLC_CODEC_RGB15 &&
161 out_chroma != VLC_CODEC_RGB16 &&
162 out_chroma != VLC_CODEC_RGB24 &&
163 out_chroma != VLC_CODEC_RGB32 ) )
165 return VLC_EGENERIC;
167 for( int i = 0; p_blend_cfg[i].src != 0; i++ )
169 if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma )
170 continue;
171 for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ )
173 if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma )
174 continue;
175 p_sys->i_blendcfg = i;
179 if( p_sys->i_blendcfg == -1 )
181 msg_Dbg( p_filter, "no matching alpha blending routine "
182 "(chroma: %4.4s -> %4.4s)",
183 (char *)&p_filter->fmt_in.video.i_chroma,
184 (char *)&p_filter->fmt_out.video.i_chroma );
185 free( p_sys );
186 return VLC_EGENERIC;
189 /* Misc init */
190 p_filter->pf_video_blend = Blend;
192 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
193 (char *)&p_filter->fmt_in.video.i_chroma,
194 (char *)&p_filter->fmt_out.video.i_chroma );
196 return VLC_SUCCESS;
199 /*****************************************************************************
200 * CloseFilter: clean up the filter
201 *****************************************************************************/
202 static void CloseFilter( vlc_object_t *p_this )
204 filter_t *p_filter = (filter_t*)p_this;
205 free( p_filter->p_sys );
208 /****************************************************************************
209 * Blend: the whole thing
210 ****************************************************************************
211 * This function is called just after the thread is launched.
212 ****************************************************************************/
214 static void Blend( filter_t *p_filter,
215 picture_t *p_dst, const picture_t *p_src,
216 int i_x_offset, int i_y_offset, int i_alpha )
218 int i_width, i_height;
220 if( i_alpha == 0 )
221 return;
223 i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
224 (int)p_filter->fmt_in.video.i_visible_width);
226 i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
227 (int)p_filter->fmt_in.video.i_visible_height);
229 if( i_width <= 0 || i_height <= 0 )
230 return;
232 video_format_FixRgb( &p_filter->fmt_out.video );
233 video_format_FixRgb( &p_filter->fmt_in.video );
235 #if 0
236 msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s\n",
237 (char *)&p_filter->fmt_in.video.i_chroma,
238 (char *)&p_filter->fmt_out.video.i_chroma );
239 #endif
242 p_blend_cfg[p_filter->p_sys->i_blendcfg].pf_blend( p_filter, p_dst, p_src,
243 i_x_offset, i_y_offset,
244 i_width, i_height, i_alpha );
248 /***********************************************************************
249 * Utils
250 ***********************************************************************/
251 static inline uint8_t vlc_uint8( int v )
253 if( v > 255 )
254 return 255;
255 else if( v < 0 )
256 return 0;
257 return v;
260 #define MAX_TRANS 255
261 #define TRANS_BITS 8
263 static inline int vlc_blend( int v1, int v2, int a )
265 /* TODO bench if the tests really increase speed */
266 if( a == 0 )
267 return v2;
268 else if( a == MAX_TRANS )
269 return v1;
270 return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
273 static inline int vlc_alpha( int t, int a )
275 if( a == 255 )
276 return t;
277 return (t * a) / 255;
280 static inline void yuv_to_rgb( int *r, int *g, int *b,
281 uint8_t y1, uint8_t u1, uint8_t v1 )
283 /* macros used for YUV pixel conversions */
284 # define SCALEBITS 10
285 # define ONE_HALF (1 << (SCALEBITS - 1))
286 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
288 int y, cb, cr, r_add, g_add, b_add;
290 cb = u1 - 128;
291 cr = v1 - 128;
292 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
293 g_add = - FIX(0.34414*255.0/224.0) * cb
294 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
295 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
296 y = (y1 - 16) * FIX(255.0/219.0);
297 *r = vlc_uint8( (y + r_add) >> SCALEBITS );
298 *g = vlc_uint8( (y + g_add) >> SCALEBITS );
299 *b = vlc_uint8( (y + b_add) >> SCALEBITS );
300 #undef FIX
301 #undef ONE_HALF
302 #undef SCALEBITS
305 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
306 int r, int g, int b )
308 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
309 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
310 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
313 static uint8_t *vlc_plane_start( int *pi_pitch,
314 const picture_t *p_picture,
315 int i_plane,
316 int i_x_offset, int i_y_offset,
317 const video_format_t *p_fmt,
318 int r )
320 const int i_pitch = p_picture->p[i_plane].i_pitch;
321 uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
323 const int i_dx = ( i_x_offset + p_fmt->i_x_offset ) / r;
324 const int i_dy = ( i_y_offset + p_fmt->i_y_offset ) / r;
326 if( pi_pitch )
327 *pi_pitch = i_pitch;
328 return &p_pixels[ i_dy * i_pitch + i_dx ];
331 static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma )
333 static const struct {
334 vlc_fourcc_t chroma;
335 int y, u ,v;
336 } p_index[] = {
337 { VLC_CODEC_YUYV, 0, 1, 3 },
338 { VLC_CODEC_UYVY, 1, 0, 2 },
339 { VLC_CODEC_YVYU, 0, 3, 1 },
340 { VLC_CODEC_VYUY, 1, 2, 0 },
341 { 0, 0, 0, 0 }
343 int i;
345 for( i = 0; p_index[i].chroma != 0; i++ )
347 if( p_index[i].chroma == i_chroma )
348 break;
350 *pi_y = p_index[i].y;
351 *pi_u = p_index[i].u;
352 *pi_v = p_index[i].v;
355 static void vlc_blend_packed( uint8_t *p_dst,
356 int i_offset0, int i_offset1, int i_offset2,
357 int c0, int c1, int c2, int i_alpha,
358 bool b_do12 )
360 p_dst[i_offset0] = vlc_blend( c0, p_dst[i_offset0], i_alpha );
361 if( b_do12 )
363 p_dst[i_offset1] = vlc_blend( c1, p_dst[i_offset1], i_alpha );
364 p_dst[i_offset2] = vlc_blend( c2, p_dst[i_offset2], i_alpha );
368 static void vlc_blend_rgb16( uint16_t *p_dst,
369 int R, int G, int B, int i_alpha,
370 const video_format_t *p_fmt )
372 const int i_pix = *p_dst;
373 const int r = ( i_pix & p_fmt->i_rmask ) >> p_fmt->i_lrshift;
374 const int g = ( i_pix & p_fmt->i_gmask ) >> p_fmt->i_lgshift;
375 const int b = ( i_pix & p_fmt->i_bmask ) >> p_fmt->i_lbshift;
377 *p_dst = ( vlc_blend( R >> p_fmt->i_rrshift, r, i_alpha ) << p_fmt->i_lrshift ) |
378 ( vlc_blend( G >> p_fmt->i_rgshift, g, i_alpha ) << p_fmt->i_lgshift ) |
379 ( vlc_blend( B >> p_fmt->i_rbshift, b, i_alpha ) << p_fmt->i_lbshift );
382 static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex,
383 const video_format_t *p_fmt )
385 if( p_fmt->i_chroma != VLC_CODEC_RGB24 && p_fmt->i_chroma != VLC_CODEC_RGB32 )
386 return;
388 /* XXX it will works only if mask are 8 bits aligned */
389 #ifdef WORDS_BIGENDIAN
390 const int i_mask_bits = p_fmt->i_chroma == VLC_CODEC_RGB24 ? 24 : 32;
391 *pi_rindex = ( i_mask_bits - p_fmt->i_lrshift ) / 8;
392 *pi_gindex = ( i_mask_bits - p_fmt->i_lgshift ) / 8;
393 *pi_bindex = ( i_mask_bits - p_fmt->i_lbshift ) / 8;
394 #else
395 *pi_rindex = p_fmt->i_lrshift / 8;
396 *pi_gindex = p_fmt->i_lgshift / 8;
397 *pi_bindex = p_fmt->i_lbshift / 8;
398 #endif
401 /***********************************************************************
402 * YUVA
403 ***********************************************************************/
404 static void BlendYUVAI420( filter_t *p_filter,
405 picture_t *p_dst, const picture_t *p_src,
406 int i_x_offset, int i_y_offset,
407 int i_width, int i_height, int i_alpha )
409 int i_src_pitch, i_dst_pitch;
410 uint8_t *p_src_y, *p_dst_y;
411 uint8_t *p_src_u, *p_dst_u;
412 uint8_t *p_src_v, *p_dst_v;
413 uint8_t *p_trans;
414 int i_x, i_y, i_trans = 0;
415 bool b_even_scanline = i_y_offset % 2;
417 p_dst_y = vlc_plane_start( &i_dst_pitch, p_dst, Y_PLANE,
418 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 1 );
419 p_dst_u = vlc_plane_start( NULL, p_dst, U_PLANE,
420 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
421 p_dst_v = vlc_plane_start( NULL, p_dst, V_PLANE,
422 i_x_offset, i_y_offset, &p_filter->fmt_out.video, 2 );
424 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
425 0, 0, &p_filter->fmt_in.video, 1 );
426 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
427 0, 0, &p_filter->fmt_in.video, 2 );
428 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
429 0, 0, &p_filter->fmt_in.video, 2 );
430 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
431 0, 0, &p_filter->fmt_in.video, 1 );
433 /* Draw until we reach the bottom of the subtitle */
434 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
435 p_dst_y += i_dst_pitch, p_src_y += i_src_pitch,
436 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
437 p_src_u += i_src_pitch,
438 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
439 p_src_v += i_src_pitch )
441 b_even_scanline = !b_even_scanline;
443 /* Draw until we reach the end of the line */
444 for( i_x = 0; i_x < i_width; i_x++ )
446 if( p_trans )
447 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
449 if( !i_trans )
450 continue;
452 /* Blending */
453 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_trans );
454 if( b_even_scanline && i_x % 2 == 0 )
456 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x], p_dst_u[i_x/2], i_trans );
457 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x], p_dst_v[i_x/2], i_trans );
463 static void BlendYUVARV16( filter_t *p_filter,
464 picture_t *p_dst_pic, const picture_t *p_src,
465 int i_x_offset, int i_y_offset,
466 int i_width, int i_height, int i_alpha )
468 int i_src_pitch, i_dst_pitch;
469 uint8_t *p_dst, *p_src_y;
470 uint8_t *p_src_u, *p_src_v;
471 uint8_t *p_trans;
472 int i_x, i_y, i_pix_pitch, i_trans = 0;
473 int r, g, b;
475 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
476 i_dst_pitch = p_dst_pic->p->i_pitch;
477 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
478 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
479 p_dst_pic->p->i_pitch *
480 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
482 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
483 0, 0, &p_filter->fmt_in.video, 1 );
484 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
485 0, 0, &p_filter->fmt_in.video, 2 );
486 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
487 0, 0, &p_filter->fmt_in.video, 2 );
488 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
489 0, 0, &p_filter->fmt_in.video, 1 );
491 /* Draw until we reach the bottom of the subtitle */
492 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
493 p_dst += i_dst_pitch,
494 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
495 p_src_v += i_src_pitch )
497 /* Draw until we reach the end of the line */
498 for( i_x = 0; i_x < i_width; i_x++ )
500 if( p_trans )
501 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
502 if( !i_trans )
503 continue;
505 /* Blending */
506 yuv_to_rgb( &r, &g, &b,
507 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
509 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
510 r, g, b, i_trans, &p_filter->fmt_out.video );
515 static void BlendYUVARV24( filter_t *p_filter,
516 picture_t *p_dst_pic, const picture_t *p_src,
517 int i_x_offset, int i_y_offset,
518 int i_width, int i_height, int i_alpha )
520 int i_src_pitch, i_dst_pitch;
521 uint8_t *p_dst, *p_src_y;
522 uint8_t *p_src_u, *p_src_v;
523 uint8_t *p_trans;
524 int i_x, i_y, i_pix_pitch, i_trans = 0;
525 int r, g, b;
527 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
528 i_dst_pitch = p_dst_pic->p->i_pitch;
529 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
530 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
531 p_dst_pic->p->i_pitch *
532 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
534 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
535 0, 0, &p_filter->fmt_in.video, 1 );
536 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
537 0, 0, &p_filter->fmt_in.video, 2 );
538 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
539 0, 0, &p_filter->fmt_in.video, 2 );
540 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
541 0, 0, &p_filter->fmt_in.video, 1 );
543 if( (i_pix_pitch == 4)
544 && (((((intptr_t)p_dst)|i_dst_pitch) /* FIXME? */
545 & 3) == 0) )
548 ** if picture pixels are 32 bits long and lines addresses are 32 bit
549 ** aligned, optimize rendering
551 uint32_t *p32_dst = (uint32_t *)p_dst;
552 uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
554 int i_rshift, i_gshift, i_bshift;
555 uint32_t i_rmask, i_gmask, i_bmask;
557 i_rmask = p_filter->fmt_out.video.i_rmask;
558 i_gmask = p_filter->fmt_out.video.i_gmask;
559 i_bmask = p_filter->fmt_out.video.i_bmask;
560 i_rshift = p_filter->fmt_out.video.i_lrshift;
561 i_gshift = p_filter->fmt_out.video.i_lgshift;
562 i_bshift = p_filter->fmt_out.video.i_lbshift;
564 /* Draw until we reach the bottom of the subtitle */
565 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
566 p32_dst += i32_dst_pitch,
567 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
568 p_src_v += i_src_pitch )
570 /* Draw until we reach the end of the line */
571 for( i_x = 0; i_x < i_width; i_x++ )
573 if( p_trans )
574 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
575 if( !i_trans )
576 continue;
578 if( i_trans == MAX_TRANS )
580 /* Completely opaque. Completely overwrite underlying pixel */
581 yuv_to_rgb( &r, &g, &b,
582 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
584 p32_dst[i_x] = (r<<i_rshift) |
585 (g<<i_gshift) |
586 (b<<i_bshift);
588 else
590 /* Blending */
591 uint32_t i_pix_dst = p32_dst[i_x];
592 yuv_to_rgb( &r, &g, &b,
593 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
595 p32_dst[i_x] = ( vlc_blend( r, (i_pix_dst & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
596 ( vlc_blend( g, (i_pix_dst & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
597 ( vlc_blend( b, (i_pix_dst & i_bmask)>>i_bshift, i_trans ) << i_bshift );
602 else
604 int i_rindex, i_gindex, i_bindex;
605 uint32_t i_rmask, i_gmask, i_bmask;
607 i_rmask = p_filter->fmt_out.video.i_rmask;
608 i_gmask = p_filter->fmt_out.video.i_gmask;
609 i_bmask = p_filter->fmt_out.video.i_bmask;
611 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
613 /* Draw until we reach the bottom of the subtitle */
614 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
615 p_dst += i_dst_pitch,
616 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
617 p_src_v += i_src_pitch )
619 /* Draw until we reach the end of the line */
620 for( i_x = 0; i_x < i_width; i_x++ )
622 if( p_trans )
623 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
624 if( !i_trans )
625 continue;
627 /* Blending */
628 yuv_to_rgb( &r, &g, &b,
629 p_src_y[i_x], p_src_u[i_x], p_src_v[i_x] );
631 vlc_blend_packed( &p_dst[ i_x * i_pix_pitch],
632 i_rindex, i_gindex, i_bindex,
633 r, g, b, i_alpha, true );
639 static void BlendYUVAYUVPacked( filter_t *p_filter,
640 picture_t *p_dst_pic, const picture_t *p_src,
641 int i_x_offset, int i_y_offset,
642 int i_width, int i_height, int i_alpha )
644 int i_src_pitch, i_dst_pitch;
645 uint8_t *p_dst, *p_src_y;
646 uint8_t *p_src_u, *p_src_v;
647 uint8_t *p_trans;
648 int i_x, i_y, i_pix_pitch, i_trans = 0;
649 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
650 int i_l_offset, i_u_offset, i_v_offset;
652 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
653 p_filter->fmt_out.video.i_chroma );
655 i_pix_pitch = 2;
656 i_dst_pitch = p_dst_pic->p->i_pitch;
657 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
658 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
659 p_dst_pic->p->i_pitch *
660 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
662 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
663 0, 0, &p_filter->fmt_in.video, 1 );
664 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
665 0, 0, &p_filter->fmt_in.video, 2 );
666 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
667 0, 0, &p_filter->fmt_in.video, 2 );
668 p_trans = vlc_plane_start( NULL, p_src, A_PLANE,
669 0, 0, &p_filter->fmt_in.video, 1 );
671 i_width &= ~1; /* Needs to be a multiple of 2 */
673 /* Draw until we reach the bottom of the subtitle */
674 for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src_pitch,
675 p_dst += i_dst_pitch,
676 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
677 p_src_v += i_src_pitch )
679 /* Draw until we reach the end of the line */
680 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
682 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
683 if( !i_trans )
684 continue;
686 /* Blending */
687 if( b_even )
689 int i_u;
690 int i_v;
691 /* FIXME what's with 0xaa ? */
692 if( p_trans[i_x+1] > 0xaa )
694 i_u = (p_src_u[i_x]+p_src_u[i_x+1])>>1;
695 i_v = (p_src_v[i_x]+p_src_v[i_x+1])>>1;
697 else
699 i_u = p_src_u[i_x];
700 i_v = p_src_v[i_x];
703 vlc_blend_packed( &p_dst[i_x * 2],
704 i_l_offset, i_u_offset, i_v_offset,
705 p_src_y[i_x], i_u, i_v, i_trans, true );
707 else
709 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 );
714 /***********************************************************************
715 * I420, YV12
716 ***********************************************************************/
717 static void BlendI420I420( filter_t *p_filter,
718 picture_t *p_dst, const picture_t *p_src,
719 int i_x_offset, int i_y_offset,
720 int i_width, int i_height, int i_alpha )
722 int i_src_pitch, i_dst_pitch;
723 uint8_t *p_src_y, *p_dst_y;
724 uint8_t *p_src_u, *p_dst_u;
725 uint8_t *p_src_v, *p_dst_v;
726 int i_x, i_y;
727 bool b_even_scanline = i_y_offset % 2;
729 if( i_alpha == 0xff )
731 BlendI420I420_no_alpha( p_filter, p_dst, p_src,
732 i_x_offset, i_y_offset, i_width, i_height );
733 return;
737 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
738 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
739 p_filter->fmt_out.video.i_x_offset +
740 p_dst->p[Y_PLANE].i_pitch *
741 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
742 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
743 p_filter->fmt_out.video.i_x_offset/2 +
744 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
745 p_dst->p[U_PLANE].i_pitch;
746 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
747 p_filter->fmt_out.video.i_x_offset/2 +
748 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
749 p_dst->p[V_PLANE].i_pitch;
751 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
752 0, 0, &p_filter->fmt_in.video, 1 );
753 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
754 0, 0, &p_filter->fmt_in.video, 2 );
755 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
756 0, 0, &p_filter->fmt_in.video, 2 );
757 i_width &= ~1;
759 /* Draw until we reach the bottom of the subtitle */
760 for( i_y = 0; i_y < i_height; i_y++,
761 p_dst_y += i_dst_pitch,
762 p_src_y += i_src_pitch )
764 if( b_even_scanline )
766 p_dst_u += i_dst_pitch/2;
767 p_dst_v += i_dst_pitch/2;
769 b_even_scanline = !b_even_scanline;
771 /* Draw until we reach the end of the line */
772 for( i_x = 0; i_x < i_width; i_x++ )
774 if( !i_alpha )
775 continue;
777 /* Blending */
778 p_dst_y[i_x] = vlc_blend( p_src_y[i_x], p_dst_y[i_x], i_alpha );
779 if( b_even_scanline && i_x % 2 == 0 )
781 p_dst_u[i_x/2] = vlc_blend( p_src_u[i_x/2], p_dst_u[i_x/2], i_alpha );
782 p_dst_v[i_x/2] = vlc_blend( p_src_v[i_x/2], p_dst_v[i_x/2], i_alpha );
785 if( i_y%2 == 1 )
787 p_src_u += i_src_pitch/2;
788 p_src_v += i_src_pitch/2;
792 static void BlendI420I420_no_alpha( filter_t *p_filter,
793 picture_t *p_dst, const picture_t *p_src,
794 int i_x_offset, int i_y_offset,
795 int i_width, int i_height )
797 int i_src_pitch, i_dst_pitch;
798 uint8_t *p_src_y, *p_dst_y;
799 uint8_t *p_src_u, *p_dst_u;
800 uint8_t *p_src_v, *p_dst_v;
801 int i_y;
802 bool b_even_scanline = i_y_offset % 2;
804 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
805 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
806 p_filter->fmt_out.video.i_x_offset +
807 p_dst->p[Y_PLANE].i_pitch *
808 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
809 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
810 p_filter->fmt_out.video.i_x_offset/2 +
811 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
812 p_dst->p[U_PLANE].i_pitch;
813 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
814 p_filter->fmt_out.video.i_x_offset/2 +
815 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
816 p_dst->p[V_PLANE].i_pitch;
818 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
819 0, 0, &p_filter->fmt_in.video, 1 );
820 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
821 0, 0, &p_filter->fmt_in.video, 2 );
822 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
823 0, 0, &p_filter->fmt_in.video, 2 );
825 i_width &= ~1;
827 /* Draw until we reach the bottom of the subtitle */
828 for( i_y = 0; i_y < i_height;
829 i_y++, p_dst_y += i_dst_pitch, p_src_y += i_src_pitch )
831 /* Completely opaque. Completely overwrite underlying pixel */
832 vlc_memcpy( p_dst_y, p_src_y, i_width );
833 if( b_even_scanline )
835 p_dst_u += i_dst_pitch/2;
836 p_dst_v += i_dst_pitch/2;
838 else
840 vlc_memcpy( p_dst_u, p_src_u, i_width/2 );
841 vlc_memcpy( p_dst_v, p_src_v, i_width/2 );
843 b_even_scanline = !b_even_scanline;
844 if( i_y%2 == 1 )
846 p_src_u += i_src_pitch/2;
847 p_src_v += i_src_pitch/2;
852 static void BlendI420R16( filter_t *p_filter,
853 picture_t *p_dst_pic, const picture_t *p_src,
854 int i_x_offset, int i_y_offset,
855 int i_width, int i_height, int i_alpha )
857 int i_src_pitch, i_dst_pitch;
858 uint8_t *p_dst, *p_src_y;
859 uint8_t *p_src_u, *p_src_v;
860 int i_x, i_y, i_pix_pitch;
861 int r, g, b;
863 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
864 i_dst_pitch = p_dst_pic->p->i_pitch;
865 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
866 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
867 p_dst_pic->p->i_pitch *
868 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
870 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
871 0, 0, &p_filter->fmt_in.video, 1 );
872 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
873 0, 0, &p_filter->fmt_in.video, 2 );
874 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
875 0, 0, &p_filter->fmt_in.video, 2 );
877 /* Draw until we reach the bottom of the subtitle */
878 for( i_y = 0; i_y < i_height; i_y++,
879 p_dst += i_dst_pitch,
880 p_src_y += i_src_pitch )
882 /* Draw until we reach the end of the line */
883 for( i_x = 0; i_x < i_width; i_x++ )
885 /* Blending */
886 yuv_to_rgb( &r, &g, &b,
887 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
889 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
890 r, g, b, i_alpha, &p_filter->fmt_out.video );
892 if( i_y%2 == 1 )
894 p_src_u += i_src_pitch/2;
895 p_src_v += i_src_pitch/2;
900 static void BlendI420R24( filter_t *p_filter,
901 picture_t *p_dst_pic, const picture_t *p_src,
902 int i_x_offset, int i_y_offset,
903 int i_width, int i_height, int i_alpha )
905 int i_src_pitch, i_dst_pitch;
906 uint8_t *p_dst, *p_src_y;
907 uint8_t *p_src_u, *p_src_v;
908 int i_x, i_y, i_pix_pitch;
909 int i_rindex, i_gindex, i_bindex;
910 int r, g, b;
912 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
913 i_dst_pitch = p_dst_pic->p->i_pitch;
914 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
915 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
916 p_dst_pic->p->i_pitch *
917 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
919 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
920 0, 0, &p_filter->fmt_in.video, 1 );
921 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
922 0, 0, &p_filter->fmt_in.video, 2 );
923 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
924 0, 0, &p_filter->fmt_in.video, 2 );
926 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
928 /* Draw until we reach the bottom of the subtitle */
929 for( i_y = 0; i_y < i_height; i_y++,
930 p_dst += i_dst_pitch,
931 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
932 p_src_v += i_src_pitch )
934 /* Draw until we reach the end of the line */
935 for( i_x = 0; i_x < i_width; i_x++ )
937 if( !i_alpha )
938 continue;
940 /* Blending */
941 yuv_to_rgb( &r, &g, &b,
942 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2] );
944 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
945 i_rindex, i_gindex, i_bindex, r, g, b, i_alpha, true );
947 if( i_y%2 == 1 )
949 p_src_u += i_src_pitch/2;
950 p_src_v += i_src_pitch/2;
955 static void BlendI420YUVPacked( filter_t *p_filter,
956 picture_t *p_dst_pic, const picture_t *p_src,
957 int i_x_offset, int i_y_offset,
958 int i_width, int i_height, int i_alpha )
960 int i_src_pitch, i_dst_pitch;
961 uint8_t *p_dst, *p_src_y;
962 uint8_t *p_src_u, *p_src_v;
963 int i_x, i_y, i_pix_pitch;
964 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
965 int i_l_offset, i_u_offset, i_v_offset;
967 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
968 p_filter->fmt_out.video.i_chroma );
970 i_pix_pitch = 2;
971 i_dst_pitch = p_dst_pic->p->i_pitch;
972 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
973 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
974 p_dst_pic->p->i_pitch *
975 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
977 p_src_y = vlc_plane_start( &i_src_pitch, p_src, Y_PLANE,
978 0, 0, &p_filter->fmt_in.video, 1 );
979 p_src_u = vlc_plane_start( NULL, p_src, U_PLANE,
980 0, 0, &p_filter->fmt_in.video, 2 );
981 p_src_v = vlc_plane_start( NULL, p_src, V_PLANE,
982 0, 0, &p_filter->fmt_in.video, 2 );
984 i_width &= ~1; /* Needs to be a multiple of 2 */
986 /* Draw until we reach the bottom of the subtitle */
987 for( i_y = 0; i_y < i_height; i_y++,
988 p_dst += i_dst_pitch,
989 p_src_y += i_src_pitch, p_src_u += i_src_pitch,
990 p_src_v += i_src_pitch )
992 /* Draw until we reach the end of the line */
993 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
995 if( !i_alpha )
996 continue;
998 /* Blending */
999 vlc_blend_packed( &p_dst[i_x * 2],
1000 i_l_offset, i_u_offset, i_v_offset,
1001 p_src_y[i_x], p_src_u[i_x/2], p_src_v[i_x/2], i_alpha, b_even );
1003 if( i_y%2 == 1 )
1005 p_src_u += i_src_pitch/2;
1006 p_src_v += i_src_pitch/2;
1011 /***********************************************************************
1012 * YUVP
1013 ***********************************************************************/
1014 static void BlendPalI420( filter_t *p_filter,
1015 picture_t *p_dst, const picture_t *p_src_pic,
1016 int i_x_offset, int i_y_offset,
1017 int i_width, int i_height, int i_alpha )
1019 int i_src_pitch, i_dst_pitch;
1020 uint8_t *p_src, *p_dst_y;
1021 uint8_t *p_dst_u;
1022 uint8_t *p_dst_v;
1023 int i_x, i_y, i_trans;
1024 bool b_even_scanline = i_y_offset % 2;
1026 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1027 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1028 p_filter->fmt_out.video.i_x_offset +
1029 p_dst->p[Y_PLANE].i_pitch *
1030 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1031 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1032 p_filter->fmt_out.video.i_x_offset/2 +
1033 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1034 p_dst->p[U_PLANE].i_pitch;
1035 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1036 p_filter->fmt_out.video.i_x_offset/2 +
1037 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1038 p_dst->p[V_PLANE].i_pitch;
1040 i_src_pitch = p_src_pic->p->i_pitch;
1041 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1042 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1044 #define p_pal p_filter->fmt_in.video.p_palette->palette
1046 /* Draw until we reach the bottom of the subtitle */
1047 for( i_y = 0; i_y < i_height; i_y++,
1048 p_dst_y += i_dst_pitch,
1049 p_src += i_src_pitch,
1050 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1051 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0 )
1053 const uint8_t *p_trans = p_src;
1054 b_even_scanline = !b_even_scanline;
1056 /* Draw until we reach the end of the line */
1057 for( i_x = 0; i_x < i_width; i_x++ )
1059 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1060 if( !i_trans )
1061 continue;
1063 /* Blending */
1064 p_dst_y[i_x] = vlc_blend( p_pal[p_src[i_x]][0], p_dst_y[i_x], i_trans );
1065 if( b_even_scanline && ((i_x % 2) == 0) )
1067 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src[i_x]][1], p_dst_u[i_x/2], i_trans );
1068 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src[i_x]][2], p_dst_v[i_x/2], i_trans );
1072 #undef p_pal
1075 static void BlendPalYUVPacked( filter_t *p_filter,
1076 picture_t *p_dst_pic, const picture_t *p_src_pic,
1077 int i_x_offset, int i_y_offset,
1078 int i_width, int i_height, int i_alpha )
1080 int i_src_pitch, i_dst_pitch;
1081 uint8_t *p_src, *p_dst;
1082 int i_x, i_y, i_pix_pitch, i_trans;
1083 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1084 int i_l_offset, i_u_offset, i_v_offset;
1086 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1087 p_filter->fmt_out.video.i_chroma );
1089 i_pix_pitch = 2;
1090 i_dst_pitch = p_dst_pic->p->i_pitch;
1091 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1092 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1093 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1095 i_src_pitch = p_src_pic->p->i_pitch;
1096 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1097 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1099 i_width &= ~1; /* Needs to be a multiple of 2 */
1101 #define p_pal p_filter->fmt_in.video.p_palette->palette
1103 /* Draw until we reach the bottom of the subtitle */
1104 for( i_y = 0; i_y < i_height; i_y++,
1105 p_dst += i_dst_pitch, p_src += i_src_pitch )
1107 const uint8_t *p_trans = p_src;
1108 /* Draw until we reach the end of the line */
1109 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1111 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1112 if( !i_trans )
1113 continue;
1115 /* Blending */
1116 if( b_even )
1118 uint16_t i_u;
1119 uint16_t i_v;
1120 if( p_trans[i_x+1] > 0xaa )
1122 i_u = (p_pal[p_src[i_x]][1] + p_pal[p_src[i_x+1]][1]) >> 1;
1123 i_v = (p_pal[p_src[i_x]][2] + p_pal[p_src[i_x+1]][2]) >> 1;
1125 else
1127 i_u = p_pal[p_src[i_x]][1];
1128 i_v = p_pal[p_src[i_x]][2];
1131 vlc_blend_packed( &p_dst[i_x * 2],
1132 i_l_offset, i_u_offset, i_v_offset,
1133 p_pal[p_src[i_x]][0], i_u, i_v, i_trans, true );
1135 else
1137 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 );
1141 #undef p_pal
1144 static void BlendPalRV( filter_t *p_filter,
1145 picture_t *p_dst_pic, const picture_t *p_src_pic,
1146 int i_x_offset, int i_y_offset,
1147 int i_width, int i_height, int i_alpha )
1149 int i_src_pitch, i_dst_pitch;
1150 uint8_t *p_src, *p_dst;
1151 int i_x, i_y, i_pix_pitch, i_trans;
1152 video_palette_t rgbpalette;
1153 int i_rindex, i_gindex, i_bindex;
1155 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1156 i_dst_pitch = p_dst_pic->p->i_pitch;
1157 p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1158 p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1159 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1161 i_src_pitch = p_src_pic->p->i_pitch;
1162 p_src = p_src_pic->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1163 i_src_pitch * p_filter->fmt_in.video.i_y_offset;
1165 #define p_pal p_filter->fmt_in.video.p_palette->palette
1166 #define rgbpal rgbpalette.palette
1168 /* Convert palette first */
1169 for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries && i_y < 256; i_y++ )
1171 int r, g, b;
1173 yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1174 rgbpal[i_y][0] = r;
1175 rgbpal[i_y][1] = g;
1176 rgbpal[i_y][2] = b;
1179 /* */
1180 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1182 /* Draw until we reach the bottom of the subtitle */
1183 for( i_y = 0; i_y < i_height; i_y++,
1184 p_dst += i_dst_pitch, p_src += i_src_pitch )
1186 const uint8_t *p_trans = p_src;
1187 /* Draw until we reach the end of the line */
1188 for( i_x = 0; i_x < i_width; i_x++ )
1190 i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1191 if( !i_trans )
1192 continue;
1194 /* Blending */
1195 if( p_filter->fmt_out.video.i_chroma == VLC_CODEC_RGB15 || p_filter->fmt_out.video.i_chroma == VLC_CODEC_RGB16 )
1196 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1197 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1198 i_trans,
1199 &p_filter->fmt_out.video );
1200 else
1201 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1202 i_rindex, i_gindex, i_bindex,
1203 rgbpal[p_src[i_x]][0], rgbpal[p_src[i_x]][1], rgbpal[p_src[i_x]][2],
1204 i_trans, true );
1208 #undef p_pal
1209 #undef rgbpal
1212 /***********************************************************************
1213 * RGBA
1214 ***********************************************************************/
1215 static void BlendRGBAI420( filter_t *p_filter,
1216 picture_t *p_dst, const picture_t *p_src_pic,
1217 int i_x_offset, int i_y_offset,
1218 int i_width, int i_height, int i_alpha )
1220 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1221 uint8_t *p_dst_y;
1222 uint8_t *p_dst_u;
1223 uint8_t *p_dst_v;
1224 uint8_t *p_src;
1225 int i_x, i_y, i_trans;
1226 uint8_t y, u, v;
1228 bool b_even_scanline = i_y_offset % 2;
1230 i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1231 p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1232 p_filter->fmt_out.video.i_x_offset +
1233 p_dst->p[Y_PLANE].i_pitch *
1234 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1235 p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1236 p_filter->fmt_out.video.i_x_offset/2 +
1237 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1238 p_dst->p[U_PLANE].i_pitch;
1239 p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1240 p_filter->fmt_out.video.i_x_offset/2 +
1241 ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1242 p_dst->p[V_PLANE].i_pitch;
1244 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1245 i_src_pitch = p_src_pic->p->i_pitch;
1246 p_src = p_src_pic->p->p_pixels +
1247 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1248 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1251 /* Draw until we reach the bottom of the subtitle */
1252 for( i_y = 0; i_y < i_height; i_y++,
1253 p_dst_y += i_dst_pitch,
1254 p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1255 p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1256 p_src += i_src_pitch )
1258 b_even_scanline = !b_even_scanline;
1260 /* Draw until we reach the end of the line */
1261 for( i_x = 0; i_x < i_width; i_x++ )
1263 const int R = p_src[i_x * i_src_pix_pitch + 0];
1264 const int G = p_src[i_x * i_src_pix_pitch + 1];
1265 const int B = p_src[i_x * i_src_pix_pitch + 2];
1267 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1268 if( !i_trans )
1269 continue;
1271 /* Blending */
1272 rgb_to_yuv( &y, &u, &v, R, G, B );
1274 p_dst_y[i_x] = vlc_blend( y, p_dst_y[i_x], i_trans );
1275 if( b_even_scanline && i_x % 2 == 0 )
1277 p_dst_u[i_x/2] = vlc_blend( u, p_dst_u[i_x/2], i_trans );
1278 p_dst_v[i_x/2] = vlc_blend( v, p_dst_v[i_x/2], i_trans );
1284 static void BlendRGBAR24( filter_t *p_filter,
1285 picture_t *p_dst_pic, const picture_t *p_src_pic,
1286 int i_x_offset, int i_y_offset,
1287 int i_width, int i_height, int i_alpha )
1289 int i_src_pitch, i_dst_pitch;
1290 uint8_t *p_dst, *p_src;
1291 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1292 int i_rindex, i_gindex, i_bindex;
1294 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1295 i_dst_pitch = p_dst_pic->p->i_pitch;
1296 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1297 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1298 p_dst_pic->p->i_pitch *
1299 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1301 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1302 i_src_pitch = p_src_pic->p->i_pitch;
1303 p_src = p_src_pic->p->p_pixels +
1304 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1305 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1307 vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1309 /* Draw until we reach the bottom of the subtitle */
1310 for( i_y = 0; i_y < i_height; i_y++,
1311 p_dst += i_dst_pitch, p_src += i_src_pitch )
1313 /* Draw until we reach the end of the line */
1314 for( i_x = 0; i_x < i_width; i_x++ )
1316 const int R = p_src[i_x * i_src_pix_pitch + 0];
1317 const int G = p_src[i_x * i_src_pix_pitch + 1];
1318 const int B = p_src[i_x * i_src_pix_pitch + 2];
1320 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1321 if( !i_trans )
1322 continue;
1324 /* Blending */
1325 vlc_blend_packed( &p_dst[i_x * i_pix_pitch],
1326 i_rindex, i_gindex, i_bindex,
1327 R, G, B, i_trans, true );
1332 static void BlendRGBAR16( filter_t *p_filter,
1333 picture_t *p_dst_pic, const picture_t *p_src_pic,
1334 int i_x_offset, int i_y_offset,
1335 int i_width, int i_height, int i_alpha )
1337 int i_src_pitch, i_dst_pitch;
1338 uint8_t *p_dst, *p_src;
1339 int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1341 i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1342 i_dst_pitch = p_dst_pic->p->i_pitch;
1343 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1344 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1345 p_dst_pic->p->i_pitch *
1346 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1348 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1349 i_src_pitch = p_src_pic->p->i_pitch;
1350 p_src = p_src_pic->p->p_pixels +
1351 p_filter->fmt_in.video.i_x_offset * i_src_pix_pitch +
1352 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1354 /* Draw until we reach the bottom of the subtitle */
1355 for( i_y = 0; i_y < i_height; i_y++,
1356 p_dst += i_dst_pitch, p_src += i_src_pitch )
1358 /* Draw until we reach the end of the line */
1359 for( i_x = 0; i_x < i_width; i_x++ )
1361 const int R = p_src[i_x * i_src_pix_pitch + 0];
1362 const int G = p_src[i_x * i_src_pix_pitch + 1];
1363 const int B = p_src[i_x * i_src_pix_pitch + 2];
1365 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1366 if( !i_trans )
1367 continue;
1369 /* Blending */
1370 vlc_blend_rgb16( (uint16_t*)&p_dst[i_x * i_pix_pitch],
1371 R, G, B, i_trans, &p_filter->fmt_out.video );
1376 static void BlendRGBAYUVPacked( filter_t *p_filter,
1377 picture_t *p_dst_pic, const picture_t *p_src_pic,
1378 int i_x_offset, int i_y_offset,
1379 int i_width, int i_height, int i_alpha )
1381 int i_src_pitch, i_dst_pitch, i_src_pix_pitch;
1382 uint8_t *p_dst, *p_src;
1383 int i_x, i_y, i_pix_pitch, i_trans;
1384 bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1385 int i_l_offset, i_u_offset, i_v_offset;
1386 uint8_t y, u, v;
1388 vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1389 p_filter->fmt_out.video.i_chroma );
1391 i_pix_pitch = 2;
1392 i_dst_pitch = p_dst_pic->p->i_pitch;
1393 p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1394 p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1395 p_dst_pic->p->i_pitch *
1396 ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1398 i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
1399 i_src_pitch = p_src_pic->p->i_pitch;
1400 p_src = p_src_pic->p->p_pixels +
1401 p_filter->fmt_in.video.i_x_offset * i_src_pitch +
1402 p_src_pic->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1404 i_width &= ~1; /* Needs to be a multiple of 2 */
1406 /* Draw until we reach the bottom of the subtitle */
1407 for( i_y = 0; i_y < i_height; i_y++,
1408 p_dst += i_dst_pitch,
1409 p_src += i_src_pitch )
1411 /* Draw until we reach the end of the line */
1412 for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1414 const int R = p_src[i_x * i_src_pix_pitch + 0];
1415 const int G = p_src[i_x * i_src_pix_pitch + 1];
1416 const int B = p_src[i_x * i_src_pix_pitch + 2];
1418 i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
1419 if( !i_trans )
1420 continue;
1422 /* Blending */
1423 rgb_to_yuv( &y, &u, &v, R, G, B );
1425 vlc_blend_packed( &p_dst[i_x * 2],
1426 i_l_offset, i_u_offset, i_v_offset,
1427 y, u, v, i_trans, b_even );