]> git.sesse.net Git - vlc/blob - modules/video_filter/blend.c
Cosmetics.
[vlc] / modules / video_filter / blend.c
1 /*****************************************************************************
2  * blend.c: alpha blend 2 pictures together
3  *****************************************************************************
4  * Copyright (C) 2003-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *          Antoine Cellerier <dionoea @t videolan dot org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <assert.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout.h>
36 #include "vlc_filter.h"
37
38 /*****************************************************************************
39  * Module descriptor
40  *****************************************************************************/
41 static int  OpenFilter ( vlc_object_t * );
42 static void CloseFilter( vlc_object_t * );
43
44 vlc_module_begin();
45     set_description( N_("Video pictures blending") );
46     set_capability( "video blending", 100 );
47     set_callbacks( OpenFilter, CloseFilter );
48 vlc_module_end();
49
50
51 /*****************************************************************************
52  * filter_sys_t : filter descriptor
53  *****************************************************************************/
54 struct filter_sys_t
55 {
56     int i_dummy;
57 };
58
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')
62
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')
72
73 /****************************************************************************
74  * Local prototypes
75  ****************************************************************************/
76 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
77                    int, int, int );
78
79 /* YUVA */
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 );
88
89 /* I420, YV12 */
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 *,
94                            int, int, int, int );
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 );
101
102 /* YUVP */
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 );
109
110 /* RGBA */
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 );
119
120 static void video_format_FixRgb( video_format_t *p_fmt );
121
122 /*****************************************************************************
123  * OpenFilter: probe the filter and return score
124  *****************************************************************************/
125 static int OpenFilter( vlc_object_t *p_this )
126 {
127     filter_t *p_filter = (filter_t*)p_this;
128     filter_sys_t *p_sys;
129
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 ) )
142     {
143         return VLC_EGENERIC;
144     }
145
146     /* Allocate the memory needed to store the decoder's structure */
147     p_filter->p_sys = p_sys = malloc(sizeof(filter_sys_t));
148     if( !p_sys )
149         return VLC_ENOMEM;
150
151     /* Misc init */
152     p_filter->pf_video_blend = Blend;
153
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 );
157
158     return VLC_SUCCESS;
159 }
160
161 /*****************************************************************************
162  * CloseFilter: clean up the filter
163  *****************************************************************************/
164 static void CloseFilter( vlc_object_t *p_this )
165 {
166     filter_t *p_filter = (filter_t*)p_this;
167     filter_sys_t *p_sys = p_filter->p_sys;
168
169     free( p_sys );
170 }
171
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 );
180
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 }
185
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  }
191
192 static const struct
193 {
194     vlc_fourcc_t src;
195     vlc_fourcc_t p_dst[16];
196     BlendFunction pf_blend;
197 } p_blend_cfg[] = {
198
199     BLEND_CFG( FCC_YUVA, BlendYUVAI420, BlendYUVAYUVPacked, BlendYUVARV16, BlendYUVARV24 ),
200
201     BLEND_CFG( FCC_YUVP, BlendPalI420, BlendPalYUVPacked, BlendPalRV, BlendPalRV ),
202
203     BLEND_CFG( FCC_RGBA, BlendRGBAI420, BlendRGBAYUVPacked, BlendRGBAR16, BlendRGBAR24 ),
204
205     BLEND_CFG( FCC_I420, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
206
207     BLEND_CFG( FCC_YV12, BlendI420I420, BlendI420YUVPacked, BlendI420R16, BlendI420R24 ),
208
209     { 0, {0,}, NULL }
210 };
211
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 )
215 {
216     int i_width, i_height;
217
218     if( i_alpha == 0 )
219         return;
220
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);
223
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);
226
227     if( i_width <= 0 || i_height <= 0 )
228         return;
229
230     video_format_FixRgb( &p_filter->fmt_out.video );
231     video_format_FixRgb( &p_filter->fmt_in.video );
232
233 #if 0
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 );
237 #endif
238
239     for( int i = 0; p_blend_cfg[i].src != 0; i++ )
240     {
241         if( p_blend_cfg[i].src != p_filter->fmt_in.video.i_chroma )
242             continue;
243         for( int j = 0; p_blend_cfg[i].p_dst[j] != 0; j++ )
244         {
245             if( p_blend_cfg[i].p_dst[j] != p_filter->fmt_out.video.i_chroma )
246                 continue;
247
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 );
250             return;
251         }
252     }
253
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 );
258 }
259
260 /***********************************************************************
261  * Utils
262  ***********************************************************************/
263 static inline uint8_t vlc_uint8( int v )
264 {
265     if( v > 255 )
266         return 255;
267     else if( v < 0 )
268         return 0;
269     return v;
270 }
271
272 #define MAX_TRANS 255
273 #define TRANS_BITS  8
274
275 static inline int vlc_blend( int v1, int v2, int a )
276 {
277     /* TODO bench if the tests really increase speed */
278     if( a == 0 )
279         return v2;
280     else if( a == MAX_TRANS )
281         return v1;
282     return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
283 }
284
285 static inline int vlc_alpha( int t, int a )
286 {
287     if( a == 255 )
288         return t;
289     return (t * a) / 255;
290 }
291
292 static inline void yuv_to_rgb( int *r, int *g, int *b,
293                                uint8_t y1, uint8_t u1, uint8_t v1 )
294 {
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))
299
300     int y, cb, cr, r_add, g_add, b_add;
301
302     cb = u1 - 128;
303     cr = v1 - 128;
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 );
312 #undef FIX
313 #undef ONE_HALF
314 #undef SCALEBITS
315 }
316
317 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
318                                int r, int g, int b )
319 {
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 ;
323 }
324
325 static uint8_t *vlc_plane_start( int *pi_pitch,
326                                  picture_t *p_picture,
327                                  int i_plane,
328                                  int i_x_offset, int i_y_offset,
329                                  const video_format_t *p_fmt,
330                                  int r )
331 {
332     const int i_pitch = p_picture->p[i_plane].i_pitch;
333     uint8_t *p_pixels = p_picture->p[i_plane].p_pixels;
334
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;
337
338     if( pi_pitch )
339         *pi_pitch = i_pitch;
340     return &p_pixels[ i_dy * i_pitch + i_dx ];
341 }
342
343 static void vlc_yuv_packed_index( int *pi_y, int *pi_u, int *pi_v, vlc_fourcc_t i_chroma )
344 {
345     static const struct {
346         vlc_fourcc_t chroma;
347         int y, u ,v;
348     } p_index[] = {
349         { FCC_YUY2, 0, 1, 3 },
350         { FCC_UYVY, 1, 0, 2 },
351         { FCC_YVYU, 0, 3, 1 },
352         { 0, 0, 0, 0 }
353     };
354     int i;
355
356     for( i = 0; p_index[i].chroma != 0; i++ )
357     {
358         if( p_index[i].chroma == i_chroma )
359             break;
360     }
361     *pi_y = p_index[i].y;
362     *pi_u = p_index[i].u;
363     *pi_v = p_index[i].v;
364 }
365
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,
369                               bool b_do12 )
370 {
371     p_dst[i_offset0] = vlc_blend( c0, p_src[i_offset0], i_alpha );
372     if( b_do12 )
373     {
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 );
376     }
377 }
378
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 )
382 {
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;
387
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 );
391 }
392
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
397  * value.
398  *****************************************************************************/
399 static int BinaryLog( uint32_t i )
400 {
401     int i_log = 0;
402
403     if( i == 0 ) return -31337;
404
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;
410
411     return i_log;
412 }
413
414 static void vlc_rgb_index( int *pi_rindex, int *pi_gindex, int *pi_bindex,
415                            const video_format_t *p_fmt )
416 {
417     if( p_fmt->i_chroma != FCC_RV24 && p_fmt->i_chroma != FCC_RV32 )
418         return;
419
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;
426 #else
427     *pi_rindex = p_fmt->i_lrshift / 8;
428     *pi_gindex = p_fmt->i_lgshift / 8;
429     *pi_bindex = p_fmt->i_lbshift / 8;
430 #endif
431 }
432
433 /**
434  * It transforms a color mask into right and left shifts
435  * FIXME copied from video_output.c
436  */
437 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
438 {
439     uint32_t i_low, i_high;            /* lower hand higher bits of the mask */
440
441     if( !i_mask )
442     {
443         *pi_left = *pi_right = 0;
444         return;
445     }
446
447     /* Get bits */
448     i_low = i_high = i_mask;
449
450     i_low &= - (int32_t)i_low;          /* lower bit of the mask */
451     i_high += i_low;                    /* higher bit of the mask */
452
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;
457
458     /* Update pointers and return */
459     *pi_left =   i_low;
460     *pi_right = (8 - i_high + i_low);
461 }
462
463 /* FIXME should be moved to src/ */
464 static void video_format_FixRgb( video_format_t *p_fmt )
465 {
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 )
470         return;
471
472     /* FIXME find right default mask */
473     if( !p_fmt->i_rmask || !p_fmt->i_gmask || !p_fmt->i_bmask )
474     {
475         switch( p_fmt->i_chroma )
476         {
477         case FCC_RV15:
478             p_fmt->i_rmask = 0x7c00;
479             p_fmt->i_gmask = 0x03e0;
480             p_fmt->i_bmask = 0x001f;
481             break;
482
483         case FCC_RV16:
484             p_fmt->i_rmask = 0xf800;
485             p_fmt->i_gmask = 0x07e0;
486             p_fmt->i_bmask = 0x001f;
487             break;
488
489         case FCC_RV24:
490             p_fmt->i_rmask = 0xff0000;
491             p_fmt->i_gmask = 0x00ff00;
492             p_fmt->i_bmask = 0x0000ff;
493             break;
494         case FCC_RV32:
495             p_fmt->i_rmask = 0x00ff0000;
496             p_fmt->i_gmask = 0x0000ff00;
497             p_fmt->i_bmask = 0x000000ff;
498             break;
499
500         default:
501             assert(0);
502             break;
503         }
504     }
505
506     MaskToShift( &p_fmt->i_lrshift, &p_fmt->i_rrshift,
507                  p_fmt->i_rmask );
508     MaskToShift( &p_fmt->i_lgshift, &p_fmt->i_rgshift,
509                  p_fmt->i_gmask );
510     MaskToShift( &p_fmt->i_lbshift, &p_fmt->i_rbshift,
511                  p_fmt->i_bmask );
512 }
513
514 /***********************************************************************
515  * YUVA
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 )
521 {
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;
526     uint8_t *p_trans;
527     int i_x, i_y, i_trans = 0;
528     bool b_even_scanline = i_y_offset % 2;
529
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 );
536
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 );
543
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 );
552
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 )
563     {
564         b_even_scanline = !b_even_scanline;
565
566         /* Draw until we reach the end of the line */
567         for( i_x = 0; i_x < i_width; i_x++ )
568         {
569             if( p_trans )
570                 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
571
572             if( !i_trans )
573                 continue;
574
575             /* Blending */
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 )
578             {
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 );
581             }
582         }
583     }
584 }
585
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 )
590 {
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;
594     uint8_t *p_trans;
595     int i_x, i_y, i_pix_pitch, i_trans = 0;
596     int r, g, b;
597
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 );
604
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 );
610
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 );
619
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 )
625     {
626         /* Draw until we reach the end of the line */
627         for( i_x = 0; i_x < i_width; i_x++ )
628         {
629             if( p_trans )
630                 i_trans = vlc_alpha( p_trans[i_x], i_alpha );
631             if( !i_trans )
632                 continue;
633
634             /* Blending */
635             yuv_to_rgb( &r, &g, &b,
636                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
637
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 );
641         }
642     }
643 }
644
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 )
649 {
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;
653     uint8_t *p_trans;
654     int i_x, i_y, i_pix_pitch, i_trans = 0;
655     int r, g, b;
656
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 );
663
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 );
669
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 );
678
679     if( (i_pix_pitch == 4)
680      && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
681           & 3) == 0) )
682     {
683         /*
684         ** if picture pixels are 32 bits long and lines addresses are 32 bit
685         ** aligned, optimize rendering
686         */
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);
691
692         int i_rshift, i_gshift, i_bshift;
693         uint32_t i_rmask, i_gmask, i_bmask;
694
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;
701
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 )
707         {
708             /* Draw until we reach the end of the line */
709             for( i_x = 0; i_x < i_width; i_x++ )
710             {
711                 if( p_trans )
712                     i_trans = vlc_alpha( p_trans[i_x], i_alpha );
713                 if( !i_trans )
714                     continue;
715
716                 if( i_trans == MAX_TRANS )
717                 {
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] );
721
722                     p32_dst[i_x] = (r<<i_rshift) |
723                                    (g<<i_gshift) |
724                                    (b<<i_bshift);
725                 }
726                 else
727                 {
728                     /* Blending */
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] );
732
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 );
736                 }
737             }
738         }
739     }
740     else
741     {
742         int i_rindex, i_gindex, i_bindex;
743         uint32_t i_rmask, i_gmask, i_bmask;
744
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;
748
749         vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
750
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 )
756         {
757             /* Draw until we reach the end of the line */
758             for( i_x = 0; i_x < i_width; i_x++ )
759             {
760                 if( p_trans )
761                     i_trans = vlc_alpha( p_trans[i_x], i_alpha );
762                 if( !i_trans )
763                     continue;
764
765                 /* Blending */
766                 yuv_to_rgb( &r, &g, &b,
767                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
768
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 );
773             }
774         }
775     }
776 }
777
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 )
782 {
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;
786     uint8_t *p_trans;
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;
790
791     vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
792                           p_filter->fmt_out.video.i_chroma );
793
794     i_pix_pitch = 2;
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 );
800
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 );
806
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 );
815
816     i_width &= ~1; /* Needs to be a multiple of 2 */
817
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 )
823     {
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 )
826         {
827             i_trans = vlc_alpha( p_trans[i_x], i_alpha );
828             if( !i_trans )
829                 continue;
830
831             /* Blending */
832             if( b_even )
833             {
834                 int i_u;
835                 int i_v;
836                 /* FIXME what's with 0xaa ? */
837                 if( p_trans[i_x+1] > 0xaa )
838                 {
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;
841                 }
842                 else
843                 {
844                     i_u = p_src2_u[i_x];
845                     i_v = p_src2_v[i_x];
846                 }
847
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 );
851             }
852             else
853             {
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 );
855             }
856         }
857     }
858 }
859 /***********************************************************************
860  * I420, YV12
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 )
866 {
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;
871     int i_x, i_y;
872     bool b_even_scanline = i_y_offset % 2;
873
874     if( i_alpha == 0xff )
875     {
876         BlendI420I420_no_alpha( p_filter, p_dst, p_dst_orig, p_src,
877                                 i_x_offset, i_y_offset, i_width, i_height );
878         return;
879     }
880
881
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;
895
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;
909
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 );
916     i_width &= ~1;
917
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 )
922     {
923         if( b_even_scanline )
924         {
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;
929         }
930         b_even_scanline = !b_even_scanline;
931
932         /* Draw until we reach the end of the line */
933         for( i_x = 0; i_x < i_width; i_x++ )
934         {
935             if( !i_alpha )
936                 continue;
937
938             /* Blending */
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 )
941             {
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 );
944             }
945         }
946         if( i_y%2 == 1 )
947         {
948             p_src2_u += i_src2_pitch/2;
949             p_src2_v += i_src2_pitch/2;
950         }
951     }
952 }
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 )
957 {
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;
962     int i_y;
963     bool b_even_scanline = i_y_offset % 2;
964
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;
978
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 );
985
986     i_width &= ~1;
987
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 )
991     {
992         /* Completely opaque. Completely overwrite underlying pixel */
993         vlc_memcpy( p_dst_y, p_src2_y, i_width );
994         if( b_even_scanline )
995         {
996             p_dst_u  += i_dst_pitch/2;
997             p_dst_v  += i_dst_pitch/2;
998         }
999         else
1000         {
1001             vlc_memcpy( p_dst_u, p_src2_u, i_width/2 );
1002             vlc_memcpy( p_dst_v, p_src2_v, i_width/2 );
1003         }
1004         b_even_scanline = !b_even_scanline;
1005         if( i_y%2 == 1 )
1006         {
1007             p_src2_u += i_src2_pitch/2;
1008             p_src2_v += i_src2_pitch/2;
1009         }
1010     }
1011 }
1012
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 )
1017 {
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;
1022     int r, g, b;
1023
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 );
1030
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 );
1036
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 );
1043
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 )
1048     {
1049         /* Draw until we reach the end of the line */
1050         for( i_x = 0; i_x < i_width; i_x++ )
1051         {
1052             /* Blending */
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] );
1055
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 );
1059         }
1060         if( i_y%2 == 1 )
1061         {
1062             p_src2_u += i_src2_pitch/2;
1063             p_src2_v += i_src2_pitch/2;
1064         }
1065     }
1066 }
1067
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 )
1072 {
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;
1078     int r, g, b;
1079
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 );
1086
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 );
1092
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 );
1099
1100     vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1101
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 )
1107     {
1108         /* Draw until we reach the end of the line */
1109         for( i_x = 0; i_x < i_width; i_x++ )
1110         {
1111             if( !i_alpha )
1112                 continue;
1113
1114             /* Blending */
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] );
1117
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 );
1120         }
1121         if( i_y%2 == 1 )
1122         {
1123             p_src2_u += i_src2_pitch/2;
1124             p_src2_v += i_src2_pitch/2;
1125         }
1126     }
1127 }
1128
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 )
1133 {
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;
1140
1141     vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1142                           p_filter->fmt_out.video.i_chroma );
1143
1144     i_pix_pitch = 2;
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 );
1150
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 );
1156
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 );
1163
1164     i_width &= ~1; /* Needs to be a multiple of 2 */
1165
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 )
1171     {
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 )
1174         {
1175             if( !i_alpha )
1176                 continue;
1177
1178             /* Blending */
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 );
1182         }
1183         if( i_y%2 == 1 )
1184         {
1185             p_src2_u += i_src2_pitch/2;
1186             p_src2_v += i_src2_pitch/2;
1187         }
1188     }
1189 }
1190
1191 /***********************************************************************
1192  * YUVP
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 )
1198 {
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;
1205
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;
1219
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;
1233
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;
1237
1238     const uint8_t *p_trans = p_src2;
1239 #define p_pal p_filter->fmt_in.video.p_palette->palette
1240
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 )
1249     {
1250         b_even_scanline = !b_even_scanline;
1251
1252         /* Draw until we reach the end of the line */
1253         for( i_x = 0; i_x < i_width; i_x++ )
1254         {
1255             i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1256             if( !i_trans )
1257                 continue;
1258
1259             /* Blending */
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) )
1262             {
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 );
1265             }
1266         }
1267     }
1268 #undef p_pal
1269 }
1270
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 )
1275 {
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;
1281
1282     vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1283                           p_filter->fmt_out.video.i_chroma );
1284
1285     i_pix_pitch = 2;
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 );
1290
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 );
1295
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;
1299
1300     i_width &= ~1; /* Needs to be a multiple of 2 */
1301
1302     const uint8_t *p_trans = p_src2;
1303 #define p_pal p_filter->fmt_in.video.p_palette->palette
1304
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 )
1308     {
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 )
1311         {
1312             i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1313             if( !i_trans )
1314                 continue;
1315
1316             /* Blending */
1317             if( b_even )
1318             {
1319                 uint16_t i_u;
1320                 uint16_t i_v;
1321                 if( p_trans[i_x+1] > 0xaa )
1322                 {
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;
1325                 }
1326                 else
1327                 {
1328                     i_u = p_pal[p_src2[i_x]][1];
1329                     i_v = p_pal[p_src2[i_x]][2];
1330                 }
1331
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 );
1335             }
1336             else
1337             {
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 );
1339             }
1340         }
1341     }
1342 #undef p_pal
1343 }
1344
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 )
1349 {
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;
1353     int r, g, b;
1354     video_palette_t rgbpalette;
1355     int i_rindex, i_gindex, i_bindex;
1356
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 );
1362
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 );
1367
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;
1371
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
1375
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++ )
1378     {
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;
1381     }
1382
1383     /* */
1384     vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1385
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 )
1389     {
1390         /* Draw until we reach the end of the line */
1391         for( i_x = 0; i_x < i_width; i_x++ )
1392         {
1393             i_trans = vlc_alpha( p_pal[p_trans[i_x]][3], i_alpha );
1394             if( !i_trans )
1395                 continue;
1396
1397             /* Blending */
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],
1402                                   i_trans,
1403                                   &p_filter->fmt_out.video );
1404             else
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],
1408                                   i_trans, true );
1409         }
1410     }
1411
1412 #undef p_pal
1413 #undef rgbpal
1414 }
1415
1416 /***********************************************************************
1417  * RGBA
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 )
1423 {
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;
1428     uint8_t *p_src2;
1429     int i_x, i_y, i_trans;
1430     uint8_t y, u, v;
1431
1432     bool b_even_scanline = i_y_offset % 2;
1433
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;
1447
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;
1461
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;
1467
1468
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 )
1477     {
1478         b_even_scanline = !b_even_scanline;
1479
1480         /* Draw until we reach the end of the line */
1481         for( i_x = 0; i_x < i_width; i_x++ )
1482         {
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];
1486
1487             i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1488             if( !i_trans )
1489                 continue;
1490
1491             /* Blending */
1492             rgb_to_yuv( &y, &u, &v, R, G, B );
1493
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 )
1496             {
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 );
1499             }
1500         }
1501     }
1502 }
1503
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 )
1508 {
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;
1513
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 );
1520
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 );
1526
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;
1532
1533     vlc_rgb_index( &i_rindex, &i_gindex, &i_bindex, &p_filter->fmt_out.video );
1534
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 )
1538     {
1539         /* Draw until we reach the end of the line */
1540         for( i_x = 0; i_x < i_width; i_x++ )
1541         {
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];
1545
1546             i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1547             if( !i_trans )
1548                 continue;
1549
1550             /* Blending */
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 );
1554         }
1555     }
1556 }
1557
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 )
1562 {
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;
1566
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 );
1573
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 );
1579
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;
1585
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 )
1589     {
1590         /* Draw until we reach the end of the line */
1591         for( i_x = 0; i_x < i_width; i_x++ )
1592         {
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];
1596
1597             i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1598             if( !i_trans )
1599                 continue;
1600
1601             /* Blending */
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 );
1605         }
1606     }
1607 }
1608
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 )
1613 {
1614     int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1615     uint8_t *p_dst, *p_src1, *p_src2;
1616     uint8_t *p_trans;
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;
1620     uint8_t y, u, v;
1621
1622     vlc_yuv_packed_index( &i_l_offset, &i_u_offset, &i_v_offset,
1623                           p_filter->fmt_out.video.i_chroma );
1624
1625     i_pix_pitch = 2;
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 );
1631
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 );
1637
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;
1643
1644     i_width &= ~1; /* Needs to be a multiple of 2 */
1645
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 )
1650     {
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 )
1653         {
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];
1657
1658             i_trans = vlc_alpha( p_src2[i_x * i_src_pix_pitch + 3], i_alpha );
1659             if( !i_trans )
1660                 continue;
1661
1662             /* Blending */
1663             rgb_to_yuv( &y, &u, &v, R, G, B );
1664
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 );
1668         }
1669     }
1670 }