]> git.sesse.net Git - vlc/blob - modules/video_filter/blend.c
b77dea86dce0d8fe7b2b0d4a8e3ec57009e140b1
[vlc] / modules / video_filter / blend.c
1 /*****************************************************************************
2  * blend.c: alpha blend 2 pictures together
3  *****************************************************************************
4  * Copyright (C) 2003-2007 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 #include <vlc/vlc.h>
29 #include <vlc_vout.h>
30 #include "vlc_filter.h"
31
32 /*****************************************************************************
33  * filter_sys_t : filter descriptor
34  *****************************************************************************/
35 struct filter_sys_t
36 {
37     int i_dummy;
38 };
39
40 /****************************************************************************
41  * Local prototypes
42  ****************************************************************************/
43 static int  OpenFilter ( vlc_object_t * );
44 static void CloseFilter( vlc_object_t * );
45
46 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
47                    int, int, int );
48
49 /* TODO i_alpha support for BlendR16 */
50 /* YUVA, I420, YV12 */
51 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
52                        int, int, int, int, int );
53 static void BlendI420I420( filter_t *, picture_t *, picture_t *, picture_t *,
54                            int, int, int, int );
55 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
56                       int, int, int, int, int );
57 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
58                       int, int, int, int, int );
59 static void BlendYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
60                             int, int, int, int, int );
61
62 /* YUVP */
63 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
64                           int, int, int, int, int );
65 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
66                                int, int, int, int, int );
67 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
68                         int, int, int, int, int );
69
70 /* RGBA */
71 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
72                            int, int, int, int, int );
73 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
74                                 picture_t *, int, int, int, int, int );
75 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
76                           int, int, int, int, int );
77 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
78                           int, int, int, int, int );
79
80 /*****************************************************************************
81  * Module descriptor
82  *****************************************************************************/
83 vlc_module_begin();
84     set_description( _("Video pictures blending") );
85     set_capability( "video blending", 100 );
86     set_callbacks( OpenFilter, CloseFilter );
87 vlc_module_end();
88
89 /*****************************************************************************
90  * OpenFilter: probe the filter and return score
91  *****************************************************************************/
92 static int OpenFilter( vlc_object_t *p_this )
93 {
94     filter_t *p_filter = (filter_t*)p_this;
95     filter_sys_t *p_sys;
96
97     /* Check if we can handle that format.
98      * We could try to use a chroma filter if we can't. */
99     int in_chroma = p_filter->fmt_in.video.i_chroma;
100     int out_chroma = p_filter->fmt_out.video.i_chroma;
101     if( ( in_chroma  != VLC_FOURCC('Y','U','V','A') &&
102           in_chroma  != VLC_FOURCC('I','4','2','0') &&
103           in_chroma  != VLC_FOURCC('Y','V','1','2') &&
104           in_chroma  != VLC_FOURCC('Y','U','V','P') &&
105           in_chroma  != VLC_FOURCC('R','G','B','A') ) ||
106         ( out_chroma != VLC_FOURCC('I','4','2','0') &&
107           out_chroma != VLC_FOURCC('Y','U','Y','2') &&
108           out_chroma != VLC_FOURCC('Y','V','1','2') &&
109           out_chroma != VLC_FOURCC('U','Y','V','Y') &&
110           out_chroma != VLC_FOURCC('Y','V','Y','U') &&
111           out_chroma != VLC_FOURCC('R','V','1','6') &&
112           out_chroma != VLC_FOURCC('R','V','2','4') &&
113           out_chroma != VLC_FOURCC('R','V','3','2') ) )
114     {
115         return VLC_EGENERIC;
116     }
117
118     /* Allocate the memory needed to store the decoder's structure */
119     if( ( p_filter->p_sys = p_sys =
120           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
121     {
122         msg_Err( p_filter, "out of memory" );
123         return VLC_EGENERIC;
124     }
125
126     /* Misc init */
127     p_filter->pf_video_blend = Blend;
128
129     msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
130              (char *)&p_filter->fmt_in.video.i_chroma,
131              (char *)&p_filter->fmt_out.video.i_chroma );
132
133
134     return VLC_SUCCESS;
135 }
136
137 /*****************************************************************************
138  * CloseFilter: clean up the filter
139  *****************************************************************************/
140 static void CloseFilter( vlc_object_t *p_this )
141 {
142     filter_t *p_filter = (filter_t*)p_this;
143     filter_sys_t *p_sys = p_filter->p_sys;
144
145     free( p_sys );
146 }
147
148 /****************************************************************************
149  * Blend: the whole thing
150  ****************************************************************************
151  * This function is called just after the thread is launched.
152  ****************************************************************************/
153 static void Blend( filter_t *p_filter, picture_t *p_dst,
154                    picture_t *p_dst_orig, picture_t *p_src,
155                    int i_x_offset, int i_y_offset, int i_alpha )
156 {
157     int i_width, i_height;
158
159     if( i_alpha == 0 ) return;
160
161     i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
162                     (int)p_filter->fmt_in.video.i_visible_width);
163
164     i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
165                      (int)p_filter->fmt_in.video.i_visible_height);
166
167     if( i_width <= 0 || i_height <= 0 ) return;
168
169 #if 0
170     printf( "chroma: %4.4s -> %4.4s\n",
171              (char *)&p_filter->fmt_in.video.i_chroma,
172              (char *)&p_filter->fmt_out.video.i_chroma );
173 #endif
174
175     switch( p_filter->fmt_in.video.i_chroma )
176     {
177         case VLC_FOURCC('Y','V','1','2'):
178         case VLC_FOURCC('I','4','2','0'):
179             if( i_alpha == 0xff &&
180               ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('I','4','2','0')
181              || p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2')
182               ) )
183             {
184                 BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
185                                i_x_offset, i_y_offset,
186                                i_width, i_height );
187                 return;
188             }
189         case VLC_FOURCC('Y','U','V','A'):
190             switch( p_filter->fmt_out.video.i_chroma )
191             {
192                 case VLC_FOURCC('I','4','2','0'):
193                 case VLC_FOURCC('Y','V','1','2'):
194                     BlendI420( p_filter, p_dst, p_dst_orig, p_src,
195                                i_x_offset, i_y_offset,
196                                i_width, i_height, i_alpha );
197                     return;
198                 case VLC_FOURCC('Y','U','Y','2'):
199                 case VLC_FOURCC('U','Y','V','Y'):
200                 case VLC_FOURCC('Y','V','Y','U'):
201                     BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
202                                     i_x_offset, i_y_offset,
203                                     i_width, i_height, i_alpha );
204                     return;
205                 case VLC_FOURCC('R','V','1','6'):
206                     BlendR16( p_filter, p_dst, p_dst_orig, p_src,
207                               i_x_offset, i_y_offset,
208                               i_width, i_height, i_alpha );
209                     return;
210                 case VLC_FOURCC('R','V','2','4'):
211                 case VLC_FOURCC('R','V','3','2'):
212                     BlendR24( p_filter, p_dst, p_dst_orig, p_src,
213                               i_x_offset, i_y_offset,
214                               i_width, i_height, i_alpha );
215                     return;
216             }
217         case VLC_FOURCC('Y','U','V','P'):
218             switch( p_filter->fmt_out.video.i_chroma )
219             {
220                 case VLC_FOURCC('I','4','2','0'):
221                 case VLC_FOURCC('Y','V','1','2'):
222                     BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
223                                   i_x_offset, i_y_offset,
224                                   i_width, i_height, i_alpha );
225                     return;
226                 case VLC_FOURCC('Y','U','Y','2'):
227                 case VLC_FOURCC('U','Y','V','Y'):
228                 case VLC_FOURCC('Y','V','Y','U'):
229                     BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
230                                        i_x_offset, i_y_offset,
231                                        i_width, i_height, i_alpha );
232                     return;
233                 case VLC_FOURCC('R','V','1','6'):
234                 case VLC_FOURCC('R','V','2','4'):
235                 case VLC_FOURCC('R','V','3','2'):
236                     BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
237                                 i_x_offset, i_y_offset,
238                                 i_width, i_height, i_alpha );
239                     return;
240             }
241         case VLC_FOURCC('R','G','B','A'):
242             switch( p_filter->fmt_out.video.i_chroma )
243             {
244                 case VLC_FOURCC('I','4','2','0'):
245                 case VLC_FOURCC('Y','V','1','2'):
246                     BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
247                                    i_x_offset, i_y_offset,
248                                    i_width, i_height, i_alpha );
249                     return;
250                 case VLC_FOURCC('Y','U','Y','2'):
251                 case VLC_FOURCC('U','Y','V','Y'):
252                 case VLC_FOURCC('Y','V','Y','U'):
253                     BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
254                                         i_x_offset, i_y_offset,
255                                         i_width, i_height, i_alpha );
256                     return;
257                 case VLC_FOURCC('R','V','2','4'):
258                 case VLC_FOURCC('R','V','3','2'):
259                     BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
260                                   i_x_offset, i_y_offset,
261                                   i_width, i_height, i_alpha );
262                     return;
263                 case VLC_FOURCC('R','V','1','6'):
264                     BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
265                                   i_x_offset, i_y_offset,
266                                   i_width, i_height, i_alpha );
267                     return;
268             }
269     }
270
271     msg_Dbg( p_filter, "no matching alpha blending routine "
272              "(chroma: %4.4s -> %4.4s)",
273              (char *)&p_filter->fmt_in.video.i_chroma,
274              (char *)&p_filter->fmt_out.video.i_chroma );
275 }
276
277 /***********************************************************************
278  * Utils
279  ***********************************************************************/
280 static inline void yuv_to_rgb( int *r, int *g, int *b,
281                                uint8_t y1, uint8_t u1, uint8_t v1 )
282 {
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))
287 #   define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
288
289     int y, cb, cr, r_add, g_add, b_add;
290
291     cb = u1 - 128;
292     cr = v1 - 128;
293     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
294     g_add = - FIX(0.34414*255.0/224.0) * cb
295             - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
296     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
297     y = (y1 - 16) * FIX(255.0/219.0);
298     *r = CLAMP((y + r_add) >> SCALEBITS);
299     *g = CLAMP((y + g_add) >> SCALEBITS);
300     *b = CLAMP((y + b_add) >> SCALEBITS);
301 }
302
303 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
304                                int r, int g, int b )
305 {
306     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
307     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
308     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
309 }
310
311 /***********************************************************************
312  * YUVA
313  ***********************************************************************/
314 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
315                        picture_t *p_dst_orig, picture_t *p_src,
316                        int i_x_offset, int i_y_offset,
317                        int i_width, int i_height, int i_alpha )
318 {
319     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
320     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
321     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
322     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
323     uint8_t *p_trans;
324     int i_x, i_y, i_trans = 0;
325     vlc_bool_t b_even_scanline = i_y_offset % 2;
326
327     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
328     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
329               p_filter->fmt_out.video.i_x_offset +
330               p_dst->p[Y_PLANE].i_pitch *
331               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
332     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
333               p_filter->fmt_out.video.i_x_offset/2 +
334               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
335               p_dst->p[U_PLANE].i_pitch;
336     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
337               p_filter->fmt_out.video.i_x_offset/2 +
338               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
339               p_dst->p[V_PLANE].i_pitch;
340
341     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
342     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
343                p_filter->fmt_out.video.i_x_offset +
344                p_dst_orig->p[Y_PLANE].i_pitch *
345                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
346     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
347                p_filter->fmt_out.video.i_x_offset/2 +
348                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
349                p_dst_orig->p[U_PLANE].i_pitch;
350     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
351                p_filter->fmt_out.video.i_x_offset/2 +
352                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
353                p_dst_orig->p[V_PLANE].i_pitch;
354
355     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
356     p_src2_y = p_src->p[Y_PLANE].p_pixels +
357                p_filter->fmt_in.video.i_x_offset +
358                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
359     p_src2_u = p_src->p[U_PLANE].p_pixels +
360                p_filter->fmt_in.video.i_x_offset/2 +
361                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
362     p_src2_v = p_src->p[V_PLANE].p_pixels +
363                p_filter->fmt_in.video.i_x_offset/2 +
364                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
365
366     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
367         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('I','4','2','0') )
368     {
369         p_trans = NULL;
370         i_trans = i_alpha;
371     }
372     else
373     {
374         p_trans = p_src->p[A_PLANE].p_pixels +
375                   p_filter->fmt_in.video.i_x_offset +
376                   p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
377     }
378
379 #define MAX_TRANS 255
380 #define TRANS_BITS  8
381
382     /* Draw until we reach the bottom of the subtitle */
383     for( i_y = 0; i_y < i_height; i_y++, p_trans += p_trans?i_src2_pitch:0,
384          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
385          p_src2_y += i_src2_pitch,
386          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
387          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
388          p_src2_u += i_src2_pitch,
389          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
390          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
391          p_src2_v += i_src2_pitch )
392     {
393         b_even_scanline = !b_even_scanline;
394
395         /* Draw until we reach the end of the line */
396         for( i_x = 0; i_x < i_width; i_x++ )
397         {
398             if( p_trans )
399                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
400             if( !i_trans )
401             {
402                 /* Completely transparent. Don't change pixel */
403                 continue;
404             }
405             else if( i_trans == MAX_TRANS )
406             {
407                 /* Completely opaque. Completely overwrite underlying pixel */
408                 p_dst_y[i_x] = p_src2_y[i_x];
409
410                 if( b_even_scanline && i_x % 2 == 0 )
411                 {
412                     p_dst_u[i_x/2] = p_src2_u[i_x];
413                     p_dst_v[i_x/2] = p_src2_v[i_x];
414                 }
415                 continue;
416             }
417
418             /* Blending */
419             p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
420                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
421                 >> TRANS_BITS;
422
423             if( b_even_scanline && i_x % 2 == 0 )
424             {
425                 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
426                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
427                 >> TRANS_BITS;
428                 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
429                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
430                 >> TRANS_BITS;
431             }
432         }
433     }
434
435 #undef MAX_TRANS
436 #undef TRANS_BITS
437
438     return;
439 }
440 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
441                            picture_t *p_dst_orig, picture_t *p_src,
442                            int i_x_offset, int i_y_offset,
443                            int i_width, int i_height )
444 {
445     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
446     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
447     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
448     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
449     int i_y;
450     vlc_bool_t b_even_scanline = i_y_offset % 2;
451
452     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
453     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
454               p_filter->fmt_out.video.i_x_offset +
455               p_dst->p[Y_PLANE].i_pitch *
456               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
457     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
458               p_filter->fmt_out.video.i_x_offset/2 +
459               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
460               p_dst->p[U_PLANE].i_pitch;
461     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
462               p_filter->fmt_out.video.i_x_offset/2 +
463               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
464               p_dst->p[V_PLANE].i_pitch;
465
466     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
467     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
468                p_filter->fmt_out.video.i_x_offset +
469                p_dst_orig->p[Y_PLANE].i_pitch *
470                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
471     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
472                p_filter->fmt_out.video.i_x_offset/2 +
473                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
474                p_dst_orig->p[U_PLANE].i_pitch;
475     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
476                p_filter->fmt_out.video.i_x_offset/2 +
477                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
478                p_dst_orig->p[V_PLANE].i_pitch;
479
480     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
481     p_src2_y = p_src->p[Y_PLANE].p_pixels +
482                p_filter->fmt_in.video.i_x_offset +
483                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
484     p_src2_u = p_src->p[U_PLANE].p_pixels +
485                p_filter->fmt_in.video.i_x_offset/2 +
486                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
487     p_src2_v = p_src->p[V_PLANE].p_pixels +
488                p_filter->fmt_in.video.i_x_offset/2 +
489                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
490
491     i_width &= ~1;
492
493     /* Draw until we reach the bottom of the subtitle */
494     for( i_y = 0; i_y < i_height; i_y++,
495          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
496          p_src2_y += i_src2_pitch,
497          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
498          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
499          p_src2_u += i_src2_pitch,
500          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
501          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
502          p_src2_v += i_src2_pitch )
503     {
504         b_even_scanline = !b_even_scanline;
505
506         /* Completely opaque. Completely overwrite underlying pixel */
507         p_filter->p_libvlc->pf_memcpy( p_dst_y, p_src2_y, i_width );
508
509         if( b_even_scanline )
510         {
511             p_filter->p_libvlc->pf_memcpy( p_dst_u, p_src2_u, i_width/2 );
512             p_filter->p_libvlc->pf_memcpy( p_dst_y, p_src2_y, i_width/2 );
513         }
514     }
515
516     return;
517 }
518
519 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
520                       picture_t *p_dst_orig, picture_t *p_src,
521                       int i_x_offset, int i_y_offset,
522                       int i_width, int i_height, int i_alpha )
523 {
524     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
525     uint8_t *p_dst, *p_src1, *p_src2_y;
526     uint8_t *p_src2_u, *p_src2_v;
527     uint8_t *p_trans;
528     int i_x, i_y, i_pix_pitch, i_trans = 0;
529     int r, g, b;
530
531     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
532     i_dst_pitch = p_dst_pic->p->i_pitch;
533     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
534             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
535             p_dst_pic->p->i_pitch *
536             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
537
538     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
539     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
540                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
541                p_dst_orig->p->i_pitch *
542                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
543
544     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
545     p_src2_y = p_src->p[Y_PLANE].p_pixels +
546                p_filter->fmt_in.video.i_x_offset +
547                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
548     p_src2_u = p_src->p[U_PLANE].p_pixels +
549                p_filter->fmt_in.video.i_x_offset/2 +
550                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
551     p_src2_v = p_src->p[V_PLANE].p_pixels +
552                p_filter->fmt_in.video.i_x_offset/2 +
553                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
554
555     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
556         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('I','4','2','0') )
557     {
558         p_trans = NULL;
559         i_trans = i_alpha;
560     }
561     else
562     {
563         p_trans = p_src->p[A_PLANE].p_pixels +
564                   p_filter->fmt_in.video.i_x_offset +
565                   p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
566     }
567
568 #define MAX_TRANS 255
569 #define TRANS_BITS  8
570
571     /* Draw until we reach the bottom of the subtitle */
572     for( i_y = 0; i_y < i_height; i_y++, p_trans += p_trans?i_src2_pitch:0,
573          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
574          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
575          p_src2_v += i_src2_pitch )
576     {
577         /* Draw until we reach the end of the line */
578         for( i_x = 0; i_x < i_width; i_x++ )
579         {
580             if( p_trans )
581                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
582             if( !i_trans )
583             {
584                 /* Completely transparent. Don't change pixel */
585                 continue;
586             }
587             else if( i_trans == MAX_TRANS )
588             {
589                 /* Completely opaque. Completely overwrite underlying pixel */
590                 yuv_to_rgb( &r, &g, &b,
591                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
592
593     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
594                 continue;
595             }
596
597             /* Blending */
598             /* FIXME: do the blending */
599             yuv_to_rgb( &r, &g, &b,
600                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
601
602     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
603         }
604     }
605
606 #undef MAX_TRANS
607 #undef TRANS_BITS
608
609     return;
610 }
611
612 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
613                       picture_t *p_dst_orig, picture_t *p_src,
614                       int i_x_offset, int i_y_offset,
615                       int i_width, int i_height, int i_alpha )
616 {
617     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
618     uint8_t *p_dst, *p_src1, *p_src2_y;
619     uint8_t *p_src2_u, *p_src2_v;
620     uint8_t *p_trans;
621     int i_x, i_y, i_pix_pitch, i_trans = 0;
622     int r, g, b;
623
624     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
625     i_dst_pitch = p_dst_pic->p->i_pitch;
626     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
627             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
628             p_dst_pic->p->i_pitch *
629             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
630
631     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
632     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
633                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
634                p_dst_orig->p->i_pitch *
635                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
636
637     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
638     p_src2_y = p_src->p[Y_PLANE].p_pixels +
639                p_filter->fmt_in.video.i_x_offset +
640                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
641     p_src2_u = p_src->p[U_PLANE].p_pixels +
642                p_filter->fmt_in.video.i_x_offset/2 +
643                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
644     p_src2_v = p_src->p[V_PLANE].p_pixels +
645                p_filter->fmt_in.video.i_x_offset/2 +
646                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
647
648     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
649         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('I','4','2','0') )
650     {
651         p_trans = NULL;
652         i_trans = i_alpha;
653     }
654     else
655     {
656         p_trans = p_src->p[A_PLANE].p_pixels +
657                   p_filter->fmt_in.video.i_x_offset +
658                   p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
659     }
660
661 #define MAX_TRANS 255
662 #define TRANS_BITS  8
663
664     /* Draw until we reach the bottom of the subtitle */
665     for( i_y = 0; i_y < i_height; i_y++, p_trans += p_trans?i_src2_pitch:0,
666          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
667          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
668          p_src2_v += i_src2_pitch )
669     {
670         /* Draw until we reach the end of the line */
671         for( i_x = 0; i_x < i_width; i_x++ )
672         {
673             if( p_trans )
674                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
675             if( !i_trans )
676             {
677                 /* Completely transparent. Don't change pixel */
678                 continue;
679             }
680             else if( i_trans == MAX_TRANS )
681             {
682                 /* Completely opaque. Completely overwrite underlying pixel */
683                 yuv_to_rgb( &r, &g, &b,
684                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
685
686                 p_dst[i_x * i_pix_pitch]     = r;
687                 p_dst[i_x * i_pix_pitch + 1] = g;
688                 p_dst[i_x * i_pix_pitch + 2] = b;
689                 continue;
690             }
691
692             /* Blending */
693             yuv_to_rgb( &r, &g, &b,
694                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
695
696             p_dst[i_x * i_pix_pitch]     = ( r * i_trans +
697                 (uint16_t)p_src1[i_x * i_pix_pitch] *
698                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
699             p_dst[i_x * i_pix_pitch + 1] = ( g * i_trans +
700                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
701                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
702             p_dst[i_x * i_pix_pitch + 2] = ( b * i_trans +
703                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
704                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
705         }
706     }
707
708 #undef MAX_TRANS
709 #undef TRANS_BITS
710
711     return;
712 }
713
714 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
715                             picture_t *p_dst_orig, picture_t *p_src,
716                             int i_x_offset, int i_y_offset,
717                             int i_width, int i_height, int i_alpha )
718 {
719     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
720     uint8_t *p_dst, *p_src1, *p_src2_y;
721     uint8_t *p_src2_u, *p_src2_v;
722     uint8_t *p_trans;
723     int i_x, i_y, i_pix_pitch, i_trans = 0;
724     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
725     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
726
727     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
728     {
729         i_l_offset = 0;
730         i_u_offset = 1;
731         i_v_offset = 3;
732     }
733     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
734     {
735         i_l_offset = 1;
736         i_u_offset = 0;
737         i_v_offset = 2;
738     }
739     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
740     {
741         i_l_offset = 0;
742         i_u_offset = 3;
743         i_v_offset = 1;
744     }
745
746     i_pix_pitch = 2;
747     i_dst_pitch = p_dst_pic->p->i_pitch;
748     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
749             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
750             p_dst_pic->p->i_pitch *
751             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
752
753     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
754     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
755                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
756                p_dst_orig->p->i_pitch *
757                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
758
759     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
760     p_src2_y = p_src->p[Y_PLANE].p_pixels +
761                p_filter->fmt_in.video.i_x_offset +
762                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
763     p_src2_u = p_src->p[U_PLANE].p_pixels +
764                p_filter->fmt_in.video.i_x_offset/2 +
765                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
766     p_src2_v = p_src->p[V_PLANE].p_pixels +
767                p_filter->fmt_in.video.i_x_offset/2 +
768                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
769
770     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
771         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('I','4','2','0') )
772     {
773         p_trans = NULL;
774         i_trans = i_alpha;
775     }
776     else
777     {
778         p_trans = p_src->p[A_PLANE].p_pixels +
779                   p_filter->fmt_in.video.i_x_offset +
780                   p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
781     }
782
783     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
784
785 #define MAX_TRANS 255
786 #define TRANS_BITS  8
787
788     /* Draw until we reach the bottom of the subtitle */
789     for( i_y = 0; i_y < i_height; i_y++, p_trans += p_trans?i_src2_pitch:0,
790          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
791          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
792          p_src2_v += i_src2_pitch )
793     {
794         /* Draw until we reach the end of the line */
795         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
796         {
797             if( p_trans )
798                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
799             if( !i_trans )
800             {
801                 /* Completely transparent. Don't change pixel */
802             }
803             else if( i_trans == MAX_TRANS )
804             {
805                 /* Completely opaque. Completely overwrite underlying pixel */
806                 p_dst[i_x * 2 + i_l_offset]     = p_src2_y[i_x];
807
808                 if( b_even )
809                 {
810                     if( p_trans[i_x+1] > 0xaa )
811                     {
812                         p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
813                         p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
814                     }
815                     else
816                     {
817                         p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
818                         p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
819                     }
820                 }
821             }
822             else
823             {
824                 /* Blending */
825                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)p_src2_y[i_x] * i_trans +
826                     (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
827                     >> TRANS_BITS;
828
829                 if( b_even )
830                 {
831                     uint16_t i_u = 0;
832                     uint16_t i_v = 0;
833                     if( p_trans[i_x+1] > 0xaa )
834                     {
835                         i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
836                         i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
837                     }
838                     else
839                     {
840                         i_u = p_src2_u[i_x];
841                         i_v = p_src2_v[i_x];
842                     }
843                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
844                         (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
845                         >> TRANS_BITS;
846                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
847                         (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
848                         >> TRANS_BITS;
849                 }
850             }
851         }
852     }
853
854 #undef MAX_TRANS
855 #undef TRANS_BITS
856
857     return;
858 }
859
860 /***********************************************************************
861  * YUVP
862  ***********************************************************************/
863 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
864                           picture_t *p_dst_orig, picture_t *p_src,
865                           int i_x_offset, int i_y_offset,
866                           int i_width, int i_height, int i_alpha )
867 {
868     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
869     uint8_t *p_src1_y, *p_src2, *p_dst_y;
870     uint8_t *p_src1_u, *p_dst_u;
871     uint8_t *p_src1_v, *p_dst_v;
872     int i_x, i_y, i_trans;
873     vlc_bool_t b_even_scanline = i_y_offset % 2;
874
875     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
876     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
877               p_filter->fmt_out.video.i_x_offset +
878               p_dst->p[Y_PLANE].i_pitch *
879               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
880     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
881               p_filter->fmt_out.video.i_x_offset/2 +
882               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
883               p_dst->p[U_PLANE].i_pitch;
884     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
885               p_filter->fmt_out.video.i_x_offset/2 +
886               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
887               p_dst->p[V_PLANE].i_pitch;
888
889     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
890     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
891                p_filter->fmt_out.video.i_x_offset +
892                p_dst_orig->p[Y_PLANE].i_pitch *
893                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
894     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
895                p_filter->fmt_out.video.i_x_offset/2 +
896                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
897                p_dst_orig->p[U_PLANE].i_pitch;
898     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
899                p_filter->fmt_out.video.i_x_offset/2 +
900                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
901                p_dst_orig->p[V_PLANE].i_pitch;
902
903     i_src2_pitch = p_src->p->i_pitch;
904     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
905              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
906
907 #define MAX_TRANS 255
908 #define TRANS_BITS  8
909 #define p_trans p_src2
910 #define p_pal p_filter->fmt_in.video.p_palette->palette
911
912     /* Draw until we reach the bottom of the subtitle */
913     for( i_y = 0; i_y < i_height; i_y++,
914          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
915          p_src2 += i_src2_pitch,
916          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
917          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
918          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
919          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
920     {
921         b_even_scanline = !b_even_scanline;
922
923         /* Draw until we reach the end of the line */
924         for( i_x = 0; i_x < i_width; i_x++ )
925         {
926             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
927             if( !i_trans )
928             {
929                 /* Completely transparent. Don't change pixel */
930                 continue;
931             }
932             else if( i_trans == MAX_TRANS )
933             {
934                 /* Completely opaque. Completely overwrite underlying pixel */
935                 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
936
937                 if( b_even_scanline && i_x % 2 == 0 )
938                 {
939                     p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
940                     p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
941                 }
942                 continue;
943             }
944
945             /* Blending */
946             p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
947                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
948                 >> TRANS_BITS;
949
950             if( b_even_scanline && i_x % 2 == 0 )
951             {
952                 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
953                     (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
954                     >> TRANS_BITS;
955                 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
956                     (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
957                     >> TRANS_BITS;
958             }
959         }
960     }
961
962 #undef MAX_TRANS
963 #undef TRANS_BITS
964 #undef p_trans
965 #undef p_pal
966
967     return;
968 }
969
970 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
971                                picture_t *p_dst_orig, picture_t *p_src,
972                                int i_x_offset, int i_y_offset,
973                                int i_width, int i_height, int i_alpha )
974 {
975     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
976     uint8_t *p_src1, *p_src2, *p_dst;
977     int i_x, i_y, i_pix_pitch, i_trans;
978     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
979     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
980
981     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
982     {
983         i_l_offset = 0;
984         i_u_offset = 1;
985         i_v_offset = 3;
986     }
987     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
988     {
989         i_l_offset = 1;
990         i_u_offset = 0;
991         i_v_offset = 2;
992     }
993     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
994     {
995         i_l_offset = 0;
996         i_u_offset = 3;
997         i_v_offset = 1;
998     }
999
1000     i_pix_pitch = 2;
1001     i_dst_pitch = p_dst_pic->p->i_pitch;
1002     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1003             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1004             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1005
1006     i_src1_pitch = p_dst_orig->p->i_pitch;
1007     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1008              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1009              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1010
1011     i_src2_pitch = p_src->p->i_pitch;
1012     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1013              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1014
1015     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1016
1017 #define MAX_TRANS 255
1018 #define TRANS_BITS  8
1019 #define p_trans p_src2
1020 #define p_pal p_filter->fmt_in.video.p_palette->palette
1021
1022     /* Draw until we reach the bottom of the subtitle */
1023     for( i_y = 0; i_y < i_height; i_y++,
1024          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1025     {
1026         /* Draw until we reach the end of the line */
1027         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1028         {
1029             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1030             if( !i_trans )
1031             {
1032                 /* Completely transparent. Don't change pixel */
1033             }
1034             else if( i_trans == MAX_TRANS )
1035             {
1036                 /* Completely opaque. Completely overwrite underlying pixel */
1037                 p_dst[i_x * 2 + i_l_offset]     = p_pal[p_src2[i_x]][0];
1038
1039                 if( b_even )
1040                 {
1041                     if( p_trans[i_x+1] > 0xaa )
1042                     {
1043                         p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1044                         p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1045                     }
1046                     else
1047                     {
1048                         p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1049                         p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1050                     }
1051                 }
1052             }
1053             else
1054             {
1055                 /* Blending */
1056                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1057                     i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1058                     (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1059
1060                 if( b_even )
1061                 {
1062                     uint16_t i_u = 0;
1063                     uint16_t i_v = 0;
1064                     if( p_trans[i_x+1] > 0xaa )
1065                     {
1066                         i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1067                         i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1068                     }
1069                     else
1070                     {
1071                         i_u = p_pal[p_src2[i_x]][1];
1072                         i_v = p_pal[p_src2[i_x]][2];
1073                     }
1074
1075                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1076                         i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1077                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1078                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1079                         i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1080                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1081                 }
1082             }
1083         }
1084     }
1085
1086 #undef MAX_TRANS
1087 #undef TRANS_BITS
1088 #undef p_trans
1089 #undef p_pal
1090
1091     return;
1092 }
1093
1094 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1095                         picture_t *p_dst_orig, picture_t *p_src,
1096                         int i_x_offset, int i_y_offset,
1097                         int i_width, int i_height, int i_alpha )
1098 {
1099     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1100     uint8_t *p_src1, *p_src2, *p_dst;
1101     int i_x, i_y, i_pix_pitch, i_trans;
1102     int r, g, b;
1103     video_palette_t rgbpalette;
1104
1105     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1106     i_dst_pitch = p_dst_pic->p->i_pitch;
1107     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1108             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1109             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1110
1111     i_src1_pitch = p_dst_orig->p->i_pitch;
1112     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1113              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1114              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1115
1116     i_src2_pitch = p_src->p->i_pitch;
1117     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1118              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1119
1120 #define MAX_TRANS 255
1121 #define TRANS_BITS  8
1122 #define p_trans p_src2
1123 #define p_pal p_filter->fmt_in.video.p_palette->palette
1124 #define rgbpal rgbpalette.palette
1125
1126     /* Convert palette first */
1127     for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1128          i_y < 256; i_y++ )
1129     {
1130         yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1131
1132         if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1133         {
1134             *(uint16_t *)rgbpal[i_y] =
1135                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1136         }
1137         else
1138         {
1139             rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1140         }
1141     }
1142
1143     /* Draw until we reach the bottom of the subtitle */
1144     for( i_y = 0; i_y < i_height; i_y++,
1145          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1146     {
1147         /* Draw until we reach the end of the line */
1148         for( i_x = 0; i_x < i_width; i_x++ )
1149         {
1150             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1151             if( !i_trans )
1152             {
1153                 /* Completely transparent. Don't change pixel */
1154                 continue;
1155             }
1156             else if( i_trans == MAX_TRANS ||
1157                      p_filter->fmt_out.video.i_chroma ==
1158                      VLC_FOURCC('R','V','1','6') )
1159             {
1160                 /* Completely opaque. Completely overwrite underlying pixel */
1161                 p_dst[i_x * i_pix_pitch]     = rgbpal[p_src2[i_x]][0];
1162                 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1163                 if( p_filter->fmt_out.video.i_chroma !=
1164                     VLC_FOURCC('R','V','1','6') )
1165                 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1166                 continue;
1167             }
1168
1169             /* Blending */
1170             p_dst[i_x * i_pix_pitch]     = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1171                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1172                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1173             p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1174                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1175                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1176             p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1177                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1178                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1179         }
1180     }
1181
1182 #undef MAX_TRANS
1183 #undef TRANS_BITS
1184 #undef p_trans
1185 #undef p_pal
1186 #undef rgbpal
1187
1188     return;
1189 }
1190
1191 /***********************************************************************
1192  * RGBA
1193  ***********************************************************************/
1194 static void BlendRGBAI420( 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, i_src_pix_pitch;
1200     uint8_t *p_src1_y, *p_dst_y;
1201     uint8_t *p_src1_u, *p_dst_u;
1202     uint8_t *p_src1_v, *p_dst_v;
1203     uint8_t *p_src2;
1204     int i_x, i_y, i_trans;
1205     uint8_t y, u, v;
1206
1207     vlc_bool_t b_even_scanline = i_y_offset % 2;
1208
1209     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1210     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1211               p_filter->fmt_out.video.i_x_offset +
1212               p_dst->p[Y_PLANE].i_pitch *
1213               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1214     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1215               p_filter->fmt_out.video.i_x_offset/2 +
1216               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1217               p_dst->p[U_PLANE].i_pitch;
1218     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1219               p_filter->fmt_out.video.i_x_offset/2 +
1220               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1221               p_dst->p[V_PLANE].i_pitch;
1222
1223     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1224     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1225                p_filter->fmt_out.video.i_x_offset +
1226                p_dst_orig->p[Y_PLANE].i_pitch *
1227                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1228     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1229                p_filter->fmt_out.video.i_x_offset/2 +
1230                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1231                p_dst_orig->p[U_PLANE].i_pitch;
1232     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1233                p_filter->fmt_out.video.i_x_offset/2 +
1234                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1235                p_dst_orig->p[V_PLANE].i_pitch;
1236
1237     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1238     i_src2_pitch = p_src->p->i_pitch;
1239     p_src2 = p_src->p->p_pixels +
1240              p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1241              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1242
1243
1244 #define MAX_TRANS 255
1245 #define TRANS_BITS  8
1246
1247     /* Draw until we reach the bottom of the subtitle */
1248     for( i_y = 0; i_y < i_height; i_y++,
1249          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1250          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1251          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1252          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1253          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1254          p_src2 += i_src2_pitch )
1255     {
1256         b_even_scanline = !b_even_scanline;
1257
1258         /* Draw until we reach the end of the line */
1259         for( i_x = 0; i_x < i_width; i_x++ )
1260         {
1261 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1262 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1263 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1264             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1265             if( !i_trans )
1266             {
1267                 /* Completely transparent. Don't change pixel */
1268                 continue;
1269             }
1270             else if( i_trans == MAX_TRANS )
1271             {
1272                 /* Completely opaque. Completely overwrite underlying pixel */
1273                 rgb_to_yuv( &y, &u, &v, R, G, B );
1274                 p_dst_y[i_x] = y;
1275
1276                 if( b_even_scanline && i_x % 2 == 0 )
1277                 {
1278                     p_dst_u[i_x/2] = u;
1279                     p_dst_v[i_x/2] = v;
1280                 }
1281                 continue;
1282             }
1283
1284             /* Blending */
1285             rgb_to_yuv( &y, &u, &v, R, G, B );
1286             p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1287                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1288                 >> TRANS_BITS;
1289
1290             if( b_even_scanline && i_x % 2 == 0 )
1291             {
1292                 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1293                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1294                 >> TRANS_BITS;
1295                 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1296                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1297                 >> TRANS_BITS;
1298             }
1299 #undef      R
1300 #undef      G
1301 #undef      B
1302         }
1303     }
1304
1305 #undef MAX_TRANS
1306 #undef TRANS_BITS
1307
1308     return;
1309 }
1310
1311 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1312                           picture_t *p_dst_orig, picture_t *p_src,
1313                           int i_x_offset, int i_y_offset,
1314                           int i_width, int i_height, int i_alpha )
1315 {
1316     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1317     uint8_t *p_dst, *p_src1, *p_src2;
1318     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1319
1320     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1321     i_dst_pitch = p_dst_pic->p->i_pitch;
1322     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1323             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1324             p_dst_pic->p->i_pitch *
1325             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1326
1327     i_src1_pitch = p_dst_orig->p->i_pitch;
1328     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1329              p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1330              p_dst_orig->p->i_pitch *
1331              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1332
1333     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1334     i_src2_pitch = p_src->p->i_pitch;
1335     p_src2 = p_src->p->p_pixels +
1336              p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1337              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1338
1339 #define MAX_TRANS 255
1340 #define TRANS_BITS  8
1341
1342     /* Draw until we reach the bottom of the subtitle */
1343     for( i_y = 0; i_y < i_height; i_y++,
1344          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1345     {
1346         /* Draw until we reach the end of the line */
1347         for( i_x = 0; i_x < i_width; i_x++ )
1348         {
1349 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1350 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1351 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1352             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1353             if( !i_trans )
1354             {
1355                 /* Completely transparent. Don't change pixel */
1356                 continue;
1357             }
1358             else if( i_trans == MAX_TRANS )
1359             {
1360                 /* Completely opaque. Completely overwrite underlying pixel */
1361                 p_dst[i_x * i_pix_pitch + 0] = R;
1362                 p_dst[i_x * i_pix_pitch + 1] = G;
1363                 p_dst[i_x * i_pix_pitch + 2] = B;
1364                 continue;
1365             }
1366
1367             /* Blending */
1368             p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1369                 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1370                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1371             p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1372                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1373                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1374             p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1375                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1376                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1377 #undef      R
1378 #undef      G
1379 #undef      B
1380         }
1381     }
1382
1383 #undef MAX_TRANS
1384 #undef TRANS_BITS
1385
1386     return;
1387 }
1388
1389 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1390                           picture_t *p_dst_orig, picture_t *p_src,
1391                           int i_x_offset, int i_y_offset,
1392                           int i_width, int i_height, int i_alpha )
1393 {
1394     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1395     uint8_t *p_dst, *p_src1, *p_src2;
1396     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1397     uint16_t i_pix;
1398
1399     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1400     i_dst_pitch = p_dst_pic->p->i_pitch;
1401     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1402             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1403             p_dst_pic->p->i_pitch *
1404             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1405
1406     i_src1_pitch = p_dst_orig->p->i_pitch;
1407     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1408              p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1409              p_dst_orig->p->i_pitch *
1410              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1411
1412     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1413     i_src2_pitch = p_src->p->i_pitch;
1414     p_src2 = p_src->p->p_pixels +
1415              p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1416              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1417
1418 #define MAX_TRANS 255
1419 #define TRANS_BITS  8
1420
1421     /* Draw until we reach the bottom of the subtitle */
1422     for( i_y = 0; i_y < i_height; i_y++,
1423          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1424     {
1425         /* Draw until we reach the end of the line */
1426         for( i_x = 0; i_x < i_width; i_x++ )
1427         {
1428 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1429 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1430 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1431             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1432             if( !i_trans )
1433             {
1434                 /* Completely transparent. Don't change pixel */
1435                 continue;
1436             }
1437             else if( i_trans == MAX_TRANS )
1438             {
1439                 /* Completely opaque. Completely overwrite underlying pixel */
1440                 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1441                 continue;
1442             }
1443
1444             /* Blending */
1445             i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1446             *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1447                 ( ( ( (R >> 3)*i_trans
1448                     + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1449                     >> TRANS_BITS ) << 11 )
1450               | ( ( ( (G >> 2)*i_trans
1451                     + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1452                     >> TRANS_BITS ) << 5  )
1453               | ( ( ( (B >> 3)*i_trans
1454                     + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
1455                     >> TRANS_BITS ) );
1456 #undef      R
1457 #undef      G
1458 #undef      B
1459         }
1460     }
1461
1462 #undef MAX_TRANS
1463 #undef TRANS_BITS
1464
1465     return;
1466 }
1467
1468 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1469                                 picture_t *p_dst_orig, picture_t *p_src,
1470                                 int i_x_offset, int i_y_offset,
1471                                 int i_width, int i_height, int i_alpha )
1472 {
1473     int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1474     uint8_t *p_dst, *p_src1, *p_src2;
1475     uint8_t *p_trans;
1476     int i_x, i_y, i_pix_pitch, i_trans;
1477     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1478     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1479     uint8_t y, u, v;
1480
1481     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1482     {
1483         i_l_offset = 0;
1484         i_u_offset = 1;
1485         i_v_offset = 3;
1486     }
1487     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1488     {
1489         i_l_offset = 1;
1490         i_u_offset = 0;
1491         i_v_offset = 2;
1492     }
1493     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1494     {
1495         i_l_offset = 0;
1496         i_u_offset = 3;
1497         i_v_offset = 1;
1498     }
1499
1500     i_pix_pitch = 2;
1501     i_dst_pitch = p_dst_pic->p->i_pitch;
1502     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1503             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1504             p_dst_pic->p->i_pitch *
1505             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1506
1507     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1508     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1509                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1510                p_dst_orig->p->i_pitch *
1511                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1512
1513     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1514     i_src2_pitch = p_src->p->i_pitch;
1515     p_src2 = p_src->p->p_pixels +
1516              p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1517              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1518
1519     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1520
1521 #define MAX_TRANS 255
1522 #define TRANS_BITS  8
1523
1524     /* Draw until we reach the bottom of the subtitle */
1525     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
1526          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1527          p_src2 += i_src2_pitch )
1528     {
1529         /* Draw until we reach the end of the line */
1530         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1531         {
1532 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1533 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1534 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1535             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1536             if( !i_trans )
1537             {
1538                 /* Completely transparent. Don't change pixel */
1539             }
1540             else if( i_trans == MAX_TRANS )
1541             {
1542                 /* Completely opaque. Completely overwrite underlying pixel */
1543                 rgb_to_yuv( &y, &u, &v, R, G, B );
1544                 p_dst[i_x * 2 + i_l_offset] = y;
1545
1546                 if( b_even )
1547                 {
1548                     p_dst[i_x * 2 + i_u_offset] = u;
1549                     p_dst[i_x * 2 + i_v_offset] = v;
1550                 }
1551             }
1552             else
1553             {
1554                 /* Blending */
1555                 rgb_to_yuv( &y, &u, &v, R, G, B );
1556                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)y * i_trans +
1557                     (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
1558                     >> TRANS_BITS;
1559
1560                 if( b_even )
1561                 {
1562                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
1563                         (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
1564                         >> TRANS_BITS;
1565                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
1566                         (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
1567                         >> TRANS_BITS;
1568                 }
1569             }
1570         }
1571     }
1572
1573 #undef MAX_TRANS
1574 #undef TRANS_BITS
1575
1576     return;
1577 }