1 /*****************************************************************************
2 * blend.c: alpha blend 2 pictures together
3 *****************************************************************************
4 * Copyright (C) 2003-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
8 * Antoine Cellerier <dionoea @t videolan dot org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 static int OpenFilter ( vlc_object_t
* );
41 static void CloseFilter( vlc_object_t
* );
44 set_description( N_("Video pictures blending") )
45 set_capability( "video blending", 100 )
46 set_callbacks( OpenFilter
, CloseFilter
)
49 /****************************************************************************
51 ****************************************************************************/
52 static void Blend( filter_t
*, picture_t
*, const picture_t
*,
56 static void BlendYUVAI420( filter_t
*, picture_t
*, const picture_t
*,
57 int, int, int, int, int );
58 static void BlendYUVARV16( filter_t
*, picture_t
*, const picture_t
*,
59 int, int, int, int, int );
60 static void BlendYUVARV24( filter_t
*, picture_t
*, const picture_t
*,
61 int, int, int, int, int );
62 static void BlendYUVAYUVPacked( filter_t
*, picture_t
*, const picture_t
*,
63 int, int, int, int, int );
66 static void BlendI420I420( filter_t
*, picture_t
*, const picture_t
*,
67 int, int, int, int, int );
68 static void BlendI420I420_no_alpha(
69 filter_t
*, picture_t
*, const picture_t
*,
71 static void BlendI420R16( filter_t
*, picture_t
*, const picture_t
*,
72 int, int, int, int, int );
73 static void BlendI420R24( filter_t
*, picture_t
*, const picture_t
*,
74 int, int, int, int, int );
75 static void BlendI420YUVPacked( filter_t
*, picture_t
*,
76 const picture_t
*, int, int, int, int, int );
79 static void BlendPalI420( filter_t
*, picture_t
*, const picture_t
*,
80 int, int, int, int, int );
81 static void BlendPalYUVPacked( filter_t
*, picture_t
*, const picture_t
*,
82 int, int, int, int, int );
83 static void BlendPalRV( filter_t
*, picture_t
*, const picture_t
*,
84 int, int, int, int, int );
87 static void BlendRGBAI420( filter_t
*, picture_t
*, const picture_t
*,
88 int, int, int, int, int );
89 static void BlendRGBAYUVPacked( filter_t
*, picture_t
*,
90 const picture_t
*, int, int, int, int, int );
91 static void BlendRGBAR16( filter_t
*, picture_t
*, const picture_t
*,
92 int, int, int, int, int );
93 static void BlendRGBAR24( filter_t
*, picture_t
*, const picture_t
*,
94 int, int, int, int, int );
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 }
119 vlc_fourcc_t p_dst
[16];
120 BlendFunction pf_blend
;
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
),
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
) );
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
) )
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
)
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
)
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
);
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
);
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
;
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 )
232 video_format_FixRgb( &p_filter
->fmt_out
.video
);
233 video_format_FixRgb( &p_filter
->fmt_in
.video
);
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
);
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 /***********************************************************************
250 ***********************************************************************/
251 static inline uint8_t vlc_uint8( int v
)
260 #define MAX_TRANS 255
263 static inline int vlc_blend( int v1
, int v2
, int a
)
265 /* TODO bench if the tests really increase speed */
268 else if( a
== MAX_TRANS
)
270 return ( v1
* a
+ v2
* (MAX_TRANS
- a
) ) >> TRANS_BITS
;
273 static inline int vlc_alpha( int t
, int a
)
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
;
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
);
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
,
316 int i_x_offset
, int i_y_offset
,
317 const video_format_t
*p_fmt
,
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
;
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 {
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 },
345 for( i
= 0; p_index
[i
].chroma
!= 0; i
++ )
347 if( p_index
[i
].chroma
== i_chroma
)
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
,
360 p_dst
[i_offset0
] = vlc_blend( c0
, p_dst
[i_offset0
], i_alpha
);
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
)
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;
395 *pi_rindex
= p_fmt
->i_lrshift
/ 8;
396 *pi_gindex
= p_fmt
->i_lgshift
/ 8;
397 *pi_bindex
= p_fmt
->i_lbshift
/ 8;
401 /***********************************************************************
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
;
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
++ )
447 i_trans
= vlc_alpha( p_trans
[i_x
], i_alpha
);
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
;
472 int i_x
, i_y
, i_pix_pitch
, i_trans
= 0;
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
++ )
501 i_trans
= vlc_alpha( p_trans
[i_x
], i_alpha
);
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
;
524 int i_x
, i_y
, i_pix_pitch
, i_trans
= 0;
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? */
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
++ )
574 i_trans
= vlc_alpha( p_trans
[i_x
], i_alpha
);
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
) |
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
);
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
++ )
623 i_trans
= vlc_alpha( p_trans
[i_x
], i_alpha
);
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
;
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
);
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
);
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;
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 );
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 /***********************************************************************
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
;
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
);
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 );
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
++ )
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
);
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
;
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 );
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;
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
;
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
;
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
++ )
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
);
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
;
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
++ )
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 );
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
);
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
)
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
);
1005 p_src_u
+= i_src_pitch
/2;
1006 p_src_v
+= i_src_pitch
/2;
1011 /***********************************************************************
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
;
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
);
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
);
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
);
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
);
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;
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 );
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
);
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
++ )
1173 yuv_to_rgb( &r
, &g
, &b
, p_pal
[i_y
][0], p_pal
[i_y
][1], p_pal
[i_y
][2] );
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
);
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],
1199 &p_filter
->fmt_out
.video
);
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],
1212 /***********************************************************************
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
;
1225 int i_x
, i_y
, i_trans
;
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
);
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
);
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
);
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
;
1388 vlc_yuv_packed_index( &i_l_offset
, &i_u_offset
, &i_v_offset
,
1389 p_filter
->fmt_out
.video
.i_chroma
);
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
);
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
);