]> git.sesse.net Git - vlc/blob - modules/video_filter/blend.c
- blend.c: fix for BlendRV24, needs testing, dionoea ?
[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 */
51 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
52                        int, int, int, int, int );
53 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
54                       int, int, int, int, int );
55 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
56                       int, int, int, int, int );
57 static void BlendYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
58                             int, int, int, int, int );
59
60 /* I420, YV12 */
61 static void BlendI420I420( filter_t *, picture_t *, picture_t *, picture_t *,
62                            int, int, int, int, int );
63 static void BlendI420I420_no_alpha(
64                            filter_t *, picture_t *, picture_t *, picture_t *,
65                            int, int, int, int );
66 static void BlendI420R16( filter_t *, picture_t *, picture_t *, picture_t *,
67                            int, int, int, int, int );
68 static void BlendI420R24( filter_t *, picture_t *, picture_t *, picture_t *,
69                           int, int, int, int, int );
70 static void BlendI420YUVPacked( filter_t *, picture_t *, picture_t *,
71                                 picture_t *, int, int, int, int, int );
72
73 /* YUVP */
74 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
75                           int, int, int, int, int );
76 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
77                                int, int, int, int, int );
78 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
79                         int, int, int, int, int );
80
81 /* RGBA */
82 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
83                            int, int, int, int, int );
84 static void BlendRGBAYUVPacked( filter_t *, picture_t *, picture_t *,
85                                 picture_t *, int, int, int, int, int );
86 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
87                           int, int, int, int, int );
88 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
89                           int, int, int, int, int );
90
91 /*****************************************************************************
92  * Module descriptor
93  *****************************************************************************/
94 vlc_module_begin();
95     set_description( _("Video pictures blending") );
96     set_capability( "video blending", 100 );
97     set_callbacks( OpenFilter, CloseFilter );
98 vlc_module_end();
99
100 /*****************************************************************************
101  * OpenFilter: probe the filter and return score
102  *****************************************************************************/
103 static int OpenFilter( vlc_object_t *p_this )
104 {
105     filter_t *p_filter = (filter_t*)p_this;
106     filter_sys_t *p_sys;
107
108     /* Check if we can handle that format.
109      * We could try to use a chroma filter if we can't. */
110     int in_chroma = p_filter->fmt_in.video.i_chroma;
111     int out_chroma = p_filter->fmt_out.video.i_chroma;
112     if( ( in_chroma  != VLC_FOURCC('Y','U','V','A') &&
113           in_chroma  != VLC_FOURCC('I','4','2','0') &&
114           in_chroma  != VLC_FOURCC('Y','V','1','2') &&
115           in_chroma  != VLC_FOURCC('Y','U','V','P') &&
116           in_chroma  != VLC_FOURCC('R','G','B','A') ) ||
117         ( out_chroma != VLC_FOURCC('I','4','2','0') &&
118           out_chroma != VLC_FOURCC('Y','U','Y','2') &&
119           out_chroma != VLC_FOURCC('Y','V','1','2') &&
120           out_chroma != VLC_FOURCC('U','Y','V','Y') &&
121           out_chroma != VLC_FOURCC('Y','V','Y','U') &&
122           out_chroma != VLC_FOURCC('R','V','1','6') &&
123           out_chroma != VLC_FOURCC('R','V','2','4') &&
124           out_chroma != VLC_FOURCC('R','V','3','2') ) )
125     {
126         return VLC_EGENERIC;
127     }
128
129     /* Allocate the memory needed to store the decoder's structure */
130     if( ( p_filter->p_sys = p_sys =
131           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
132     {
133         msg_Err( p_filter, "out of memory" );
134         return VLC_EGENERIC;
135     }
136
137     /* Misc init */
138     p_filter->pf_video_blend = Blend;
139
140     msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
141              (char *)&p_filter->fmt_in.video.i_chroma,
142              (char *)&p_filter->fmt_out.video.i_chroma );
143
144
145     return VLC_SUCCESS;
146 }
147
148 /*****************************************************************************
149  * CloseFilter: clean up the filter
150  *****************************************************************************/
151 static void CloseFilter( vlc_object_t *p_this )
152 {
153     filter_t *p_filter = (filter_t*)p_this;
154     filter_sys_t *p_sys = p_filter->p_sys;
155
156     free( p_sys );
157 }
158
159 /****************************************************************************
160  * Blend: the whole thing
161  ****************************************************************************
162  * This function is called just after the thread is launched.
163  ****************************************************************************/
164 static void Blend( filter_t *p_filter, picture_t *p_dst,
165                    picture_t *p_dst_orig, picture_t *p_src,
166                    int i_x_offset, int i_y_offset, int i_alpha )
167 {
168     int i_width, i_height;
169
170     if( i_alpha == 0 ) return;
171
172     i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
173                     (int)p_filter->fmt_in.video.i_visible_width);
174
175     i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
176                      (int)p_filter->fmt_in.video.i_visible_height);
177
178     if( i_width <= 0 || i_height <= 0 ) return;
179
180 #if 0
181     printf( "chroma: %4.4s -> %4.4s\n",
182              (char *)&p_filter->fmt_in.video.i_chroma,
183              (char *)&p_filter->fmt_out.video.i_chroma );
184 #endif
185
186     switch( p_filter->fmt_in.video.i_chroma )
187     {
188         case VLC_FOURCC('Y','U','V','A'):
189             switch( p_filter->fmt_out.video.i_chroma )
190             {
191                 case VLC_FOURCC('I','4','2','0'):
192                 case VLC_FOURCC('Y','V','1','2'):
193                     BlendI420( p_filter, p_dst, p_dst_orig, p_src,
194                                i_x_offset, i_y_offset,
195                                i_width, i_height, i_alpha );
196                     return;
197                 case VLC_FOURCC('Y','U','Y','2'):
198                 case VLC_FOURCC('U','Y','V','Y'):
199                 case VLC_FOURCC('Y','V','Y','U'):
200                     BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
201                                     i_x_offset, i_y_offset,
202                                     i_width, i_height, i_alpha );
203                     return;
204                 case VLC_FOURCC('R','V','1','6'):
205                     BlendR16( p_filter, p_dst, p_dst_orig, p_src,
206                               i_x_offset, i_y_offset,
207                               i_width, i_height, i_alpha );
208                     return;
209                 case VLC_FOURCC('R','V','2','4'):
210                 case VLC_FOURCC('R','V','3','2'):
211                     BlendR24( p_filter, p_dst, p_dst_orig, p_src,
212                               i_x_offset, i_y_offset,
213                               i_width, i_height, i_alpha );
214                     return;
215             }
216         case VLC_FOURCC('Y','U','V','P'):
217             switch( p_filter->fmt_out.video.i_chroma )
218             {
219                 case VLC_FOURCC('I','4','2','0'):
220                 case VLC_FOURCC('Y','V','1','2'):
221                     BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
222                                   i_x_offset, i_y_offset,
223                                   i_width, i_height, i_alpha );
224                     return;
225                 case VLC_FOURCC('Y','U','Y','2'):
226                 case VLC_FOURCC('U','Y','V','Y'):
227                 case VLC_FOURCC('Y','V','Y','U'):
228                     BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
229                                        i_x_offset, i_y_offset,
230                                        i_width, i_height, i_alpha );
231                     return;
232                 case VLC_FOURCC('R','V','1','6'):
233                 case VLC_FOURCC('R','V','2','4'):
234                 case VLC_FOURCC('R','V','3','2'):
235                     BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
236                                 i_x_offset, i_y_offset,
237                                 i_width, i_height, i_alpha );
238                     return;
239             }
240         case VLC_FOURCC('Y','V','1','2'):
241         case VLC_FOURCC('I','4','2','0'):
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                     if( i_alpha == 0xff )
247                         BlendI420I420_no_alpha(
248                                    p_filter, p_dst, p_dst_orig, p_src,
249                                    i_x_offset, i_y_offset,
250                                    i_width, i_height );
251                     else
252                         BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
253                                        i_x_offset, i_y_offset,
254                                        i_width, i_height, i_alpha );
255                     return;
256                 case VLC_FOURCC('Y','U','Y','2'):
257                 case VLC_FOURCC('U','Y','V','Y'):
258                 case VLC_FOURCC('Y','V','Y','U'):
259                     BlendI420YUVPacked( 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                     BlendI420R16( 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                 case VLC_FOURCC('R','V','2','4'):
269                 case VLC_FOURCC('R','V','3','2'):
270                     BlendI420R24( p_filter, p_dst, p_dst_orig, p_src,
271                                   i_x_offset, i_y_offset,
272                                   i_width, i_height, i_alpha );
273                     return;
274             }
275         case VLC_FOURCC('R','G','B','A'):
276             switch( p_filter->fmt_out.video.i_chroma )
277             {
278                 case VLC_FOURCC('I','4','2','0'):
279                 case VLC_FOURCC('Y','V','1','2'):
280                     BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
281                                    i_x_offset, i_y_offset,
282                                    i_width, i_height, i_alpha );
283                     return;
284                 case VLC_FOURCC('Y','U','Y','2'):
285                 case VLC_FOURCC('U','Y','V','Y'):
286                 case VLC_FOURCC('Y','V','Y','U'):
287                     BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
288                                         i_x_offset, i_y_offset,
289                                         i_width, i_height, i_alpha );
290                     return;
291                 case VLC_FOURCC('R','V','2','4'):
292                 case VLC_FOURCC('R','V','3','2'):
293                     BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
294                                   i_x_offset, i_y_offset,
295                                   i_width, i_height, i_alpha );
296                     return;
297                 case VLC_FOURCC('R','V','1','6'):
298                     BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
299                                   i_x_offset, i_y_offset,
300                                   i_width, i_height, i_alpha );
301                     return;
302             }
303     }
304
305     msg_Dbg( p_filter, "no matching alpha blending routine "
306              "(chroma: %4.4s -> %4.4s)",
307              (char *)&p_filter->fmt_in.video.i_chroma,
308              (char *)&p_filter->fmt_out.video.i_chroma );
309 }
310
311 /***********************************************************************
312  * Utils
313  ***********************************************************************/
314 static inline void yuv_to_rgb( int *r, int *g, int *b,
315                                uint8_t y1, uint8_t u1, uint8_t v1 )
316 {
317     /* macros used for YUV pixel conversions */
318 #   define SCALEBITS 10
319 #   define ONE_HALF  (1 << (SCALEBITS - 1))
320 #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
321 #   define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
322
323     int y, cb, cr, r_add, g_add, b_add;
324
325     cb = u1 - 128;
326     cr = v1 - 128;
327     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
328     g_add = - FIX(0.34414*255.0/224.0) * cb
329             - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
330     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
331     y = (y1 - 16) * FIX(255.0/219.0);
332     *r = CLAMP((y + r_add) >> SCALEBITS);
333     *g = CLAMP((y + g_add) >> SCALEBITS);
334     *b = CLAMP((y + b_add) >> SCALEBITS);
335 }
336
337 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
338                                int r, int g, int b )
339 {
340     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
341     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
342     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
343 }
344
345 /***********************************************************************
346  * YUVA
347  ***********************************************************************/
348 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
349                        picture_t *p_dst_orig, picture_t *p_src,
350                        int i_x_offset, int i_y_offset,
351                        int i_width, int i_height, int i_alpha )
352 {
353     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
354     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
355     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
356     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
357     uint8_t *p_trans;
358     int i_x, i_y, i_trans = 0;
359     vlc_bool_t b_even_scanline = i_y_offset % 2;
360
361     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
362     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
363               p_filter->fmt_out.video.i_x_offset +
364               p_dst->p[Y_PLANE].i_pitch *
365               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
366     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
367               p_filter->fmt_out.video.i_x_offset/2 +
368               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
369               p_dst->p[U_PLANE].i_pitch;
370     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
371               p_filter->fmt_out.video.i_x_offset/2 +
372               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
373               p_dst->p[V_PLANE].i_pitch;
374
375     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
376     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
377                p_filter->fmt_out.video.i_x_offset +
378                p_dst_orig->p[Y_PLANE].i_pitch *
379                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
380     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
381                p_filter->fmt_out.video.i_x_offset/2 +
382                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
383                p_dst_orig->p[U_PLANE].i_pitch;
384     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
385                p_filter->fmt_out.video.i_x_offset/2 +
386                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
387                p_dst_orig->p[V_PLANE].i_pitch;
388
389     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
390     p_src2_y = p_src->p[Y_PLANE].p_pixels +
391                p_filter->fmt_in.video.i_x_offset +
392                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
393     p_src2_u = p_src->p[U_PLANE].p_pixels +
394                p_filter->fmt_in.video.i_x_offset/2 +
395                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
396     p_src2_v = p_src->p[V_PLANE].p_pixels +
397                p_filter->fmt_in.video.i_x_offset/2 +
398                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
399
400     p_trans = p_src->p[A_PLANE].p_pixels +
401               p_filter->fmt_in.video.i_x_offset +
402               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
403
404 #define MAX_TRANS 255
405 #define TRANS_BITS  8
406
407     /* Draw until we reach the bottom of the subtitle */
408     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
409          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
410          p_src2_y += i_src2_pitch,
411          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
412          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
413          p_src2_u += i_src2_pitch,
414          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
415          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
416          p_src2_v += i_src2_pitch )
417     {
418         b_even_scanline = !b_even_scanline;
419
420         /* Draw until we reach the end of the line */
421         for( i_x = 0; i_x < i_width; i_x++ )
422         {
423             if( p_trans )
424                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
425             if( !i_trans )
426             {
427                 /* Completely transparent. Don't change pixel */
428                 continue;
429             }
430             else if( i_trans == MAX_TRANS )
431             {
432                 /* Completely opaque. Completely overwrite underlying pixel */
433                 p_dst_y[i_x] = p_src2_y[i_x];
434
435                 if( b_even_scanline && i_x % 2 == 0 )
436                 {
437                     p_dst_u[i_x/2] = p_src2_u[i_x];
438                     p_dst_v[i_x/2] = p_src2_v[i_x];
439                 }
440                 continue;
441             }
442
443             /* Blending */
444             p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
445                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
446                 >> TRANS_BITS;
447
448             if( b_even_scanline && i_x % 2 == 0 )
449             {
450                 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
451                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
452                 >> TRANS_BITS;
453                 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
454                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
455                 >> TRANS_BITS;
456             }
457         }
458     }
459
460 #undef MAX_TRANS
461 #undef TRANS_BITS
462
463     return;
464 }
465
466 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
467                       picture_t *p_dst_orig, picture_t *p_src,
468                       int i_x_offset, int i_y_offset,
469                       int i_width, int i_height, int i_alpha )
470 {
471     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
472     uint8_t *p_dst, *p_src1, *p_src2_y;
473     uint8_t *p_src2_u, *p_src2_v;
474     uint8_t *p_trans;
475     int i_x, i_y, i_pix_pitch, i_trans = 0;
476     int r, g, b;
477
478     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
479     i_dst_pitch = p_dst_pic->p->i_pitch;
480     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
481             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
482             p_dst_pic->p->i_pitch *
483             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
484
485     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
486     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
487                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
488                p_dst_orig->p->i_pitch *
489                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
490
491     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
492     p_src2_y = p_src->p[Y_PLANE].p_pixels +
493                p_filter->fmt_in.video.i_x_offset +
494                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
495     p_src2_u = p_src->p[U_PLANE].p_pixels +
496                p_filter->fmt_in.video.i_x_offset/2 +
497                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
498     p_src2_v = p_src->p[V_PLANE].p_pixels +
499                p_filter->fmt_in.video.i_x_offset/2 +
500                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
501
502     p_trans = p_src->p[A_PLANE].p_pixels +
503               p_filter->fmt_in.video.i_x_offset +
504               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
505
506 #define MAX_TRANS 255
507 #define TRANS_BITS  8
508
509     /* Draw until we reach the bottom of the subtitle */
510     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
511          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
512          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
513          p_src2_v += i_src2_pitch )
514     {
515         /* Draw until we reach the end of the line */
516         for( i_x = 0; i_x < i_width; i_x++ )
517         {
518             if( p_trans )
519                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
520             if( !i_trans )
521             {
522                 /* Completely transparent. Don't change pixel */
523                 continue;
524             }
525             else if( i_trans == MAX_TRANS )
526             {
527                 /* Completely opaque. Completely overwrite underlying pixel */
528                 yuv_to_rgb( &r, &g, &b,
529                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
530
531     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
532                 continue;
533             }
534
535             /* Blending */
536             /* FIXME: do the blending */
537             yuv_to_rgb( &r, &g, &b,
538                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
539
540     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
541         }
542     }
543
544 #undef MAX_TRANS
545 #undef TRANS_BITS
546
547     return;
548 }
549
550 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
551                       picture_t *p_dst_orig, picture_t *p_src,
552                       int i_x_offset, int i_y_offset,
553                       int i_width, int i_height, int i_alpha )
554 {
555     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
556     uint8_t *p_dst, *p_src1, *p_src2_y;
557     uint8_t *p_src2_u, *p_src2_v;
558     uint8_t *p_trans;
559     int i_x, i_y, i_pix_pitch, i_trans = 0;
560     int r, g, b;
561
562     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
563     i_dst_pitch = p_dst_pic->p->i_pitch;
564     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
565             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
566             p_dst_pic->p->i_pitch *
567             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
568
569     i_src1_pitch = p_dst_orig->p->i_pitch;
570     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
571                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
572                p_dst_orig->p->i_pitch *
573                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
574
575     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
576     p_src2_y = p_src->p[Y_PLANE].p_pixels +
577                p_filter->fmt_in.video.i_x_offset +
578                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
579     p_src2_u = p_src->p[U_PLANE].p_pixels +
580                p_filter->fmt_in.video.i_x_offset/2 +
581                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
582     p_src2_v = p_src->p[V_PLANE].p_pixels +
583                p_filter->fmt_in.video.i_x_offset/2 +
584                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
585
586     p_trans = p_src->p[A_PLANE].p_pixels +
587               p_filter->fmt_in.video.i_x_offset +
588               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
589
590 #define MAX_TRANS 255
591 #define TRANS_BITS  8
592
593     if( (i_pix_pitch == 4)
594      && (((((int)p_dst)|((int)p_src1)|i_dst_pitch|i_src1_pitch) & 3) == 0) )
595     {
596         /*
597         ** if picture pixels are 32 bits long and lines addresses are 32 bit aligned,
598         ** optimize rendering
599         */
600         uint32_t *p32_dst = (uint32_t *)p_dst;
601         uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
602         uint32_t *p32_src1 = (uint32_t *)p_src1;
603         uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
604
605         int i_rshift, i_gshift, i_bshift;
606         uint32_t i_rmask, i_gmask, i_bmask;
607
608         if( p_dst_pic->p_heap )
609         {
610             i_rmask = p_dst_pic->p_heap->i_rmask;
611             i_gmask = p_dst_pic->p_heap->i_gmask;
612             i_bmask = p_dst_pic->p_heap->i_bmask;
613             i_rshift = p_dst_pic->p_heap->i_lrshift;
614             i_gshift = p_dst_pic->p_heap->i_lgshift;
615             i_bshift = p_dst_pic->p_heap->i_lbshift;
616         }
617         else
618         {
619             i_rmask = p_dst_pic->format.i_rmask;
620             i_gmask = p_dst_pic->format.i_gmask;
621             i_bmask = p_dst_pic->format.i_bmask;
622
623             if( (i_rmask == 0x00FF0000)
624              && (i_gmask == 0x0000FF00)
625              && (i_bmask == 0x000000FF) )
626             {
627                 /* X8R8G8B8 pixel layout */
628                 i_rshift = 16;
629                 i_bshift = 8;
630                 i_gshift = 0;
631             }
632             else if( (i_rmask == 0xFF000000)
633                   && (i_gmask == 0x00FF0000)
634                   && (i_bmask == 0x0000FF00) )
635             {
636                 /* R8G8B8X8 pixel layout */
637                 i_rshift = 24;
638                 i_bshift = 16;
639                 i_gshift = 8;
640             }
641             else
642             {
643                 goto slower;
644             }
645         }
646         /* Draw until we reach the bottom of the subtitle */
647         for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
648              p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
649              p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
650              p_src2_v += i_src2_pitch )
651         {
652             /* Draw until we reach the end of the line */
653             for( i_x = 0; i_x < i_width; i_x++ )
654             {
655                 if( p_trans )
656                     i_trans = ( p_trans[i_x] * i_alpha ) / 255;
657                 if( !i_trans )
658                 {
659                     /* Completely transparent. Don't change pixel */
660                     continue;
661                 }
662                 else if( i_trans == MAX_TRANS )
663                 {
664                     /* Completely opaque. Completely overwrite underlying pixel */
665                     yuv_to_rgb( &r, &g, &b,
666                                 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
667
668                     p32_dst[i_x] = (r<<i_rshift)
669                                  + (g<<i_gshift)
670                                  + (b<<i_bshift);
671                 }
672                 else
673                 {
674                     /* Blending */
675                     uint32_t i_pix_src1 = p32_src1[i_x];
676                     yuv_to_rgb( &r, &g, &b,
677                                 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
678
679                     p32_dst[i_x] = ( ( r * i_trans +
680                                      (uint16_t)((i_pix_src1 & i_rmask)>>i_rshift) *
681                                      (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_rshift
682                                  | ( ( g * i_trans +
683                                      (uint16_t)((i_pix_src1 & i_gmask)>>i_gshift) *
684                                      (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_gshift
685                                  | ( ( b * i_trans +
686                                      (uint16_t)((i_pix_src1 & i_bmask)>>i_bshift) *
687                                      (MAX_TRANS - i_trans) ) >> TRANS_BITS) << i_bshift;
688                 }
689             }
690         }
691     }
692     else
693     {
694         int i_rindex, i_bindex, i_gindex;
695         uint32_t i_rmask, i_gmask, i_bmask;
696
697         slower:
698
699         i_rmask = p_dst_pic->format.i_rmask;
700         i_gmask = p_dst_pic->format.i_gmask;
701         i_bmask = p_dst_pic->format.i_bmask;
702
703         /*
704         ** quick and dirty way to get byte index from mask
705         ** will only work correctly if mask are 8 bit aligned
706         ** and are 8 bit long
707         */
708 #ifdef WORDS_BIGENDIAN
709         i_rindex = ((i_rmask>>16) & 1)
710                  | ((i_rmask>>8) & 2)
711                  | ((i_rmask) & 3);
712         i_gindex = ((i_gmask>>16) & 1)
713                  | ((i_gmask>>8) & 2)
714                  | ((i_gmask) & 3);
715         i_bindex = ((i_bmask>>16) & 1)
716                  | ((i_bmask>>8) & 2)
717                  | ((i_bmask) & 3);
718 #else
719         i_rindex = ((i_rmask>>24) & 3)
720                  | ((i_rmask>>16) & 2)
721                  | ((i_rmask>>8) & 1);
722         i_gindex = ((i_gmask>>24) & 3)
723                  | ((i_gmask>>16) & 2)
724                  | ((i_gmask>>8) & 1);
725         i_bindex = ((i_bmask>>24) & 3)
726                  | ((i_bmask>>16) & 2)
727                  | ((i_bmask>>8) & 1);
728 #endif
729
730         /* Draw until we reach the bottom of the subtitle */
731         for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
732              p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
733              p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
734              p_src2_v += i_src2_pitch )
735         {
736             /* Draw until we reach the end of the line */
737             for( i_x = 0; i_x < i_width; i_x++ )
738             {
739                 if( p_trans )
740                     i_trans = ( p_trans[i_x] * i_alpha ) / 255;
741                 if( !i_trans )
742                 {
743                     /* Completely transparent. Don't change pixel */
744                     continue;
745                 }
746                 else 
747                 {
748                     int i_pos = i_x * i_pix_pitch;
749                     if( i_trans == MAX_TRANS )
750                     {
751
752                         /* Completely opaque. Completely overwrite underlying pixel */
753                         yuv_to_rgb( &r, &g, &b,
754                                     p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
755
756                         p_dst[i_pos + i_rindex ] = r;
757                         p_dst[i_pos + i_gindex ] = g;
758                         p_dst[i_pos + i_bindex ] = b;
759                     }
760                     else
761                     {
762                         int i_rpos = i_pos + i_rindex;
763                         int i_gpos = i_pos + i_gindex;
764                         int i_bpos = i_pos + i_bindex;
765
766                         /* Blending */
767                         yuv_to_rgb( &r, &g, &b,
768                                     p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
769
770                         p_dst[i_rpos] = ( r * i_trans +
771                                         (uint16_t)p_src1[i_rpos] *
772                                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
773                         p_dst[i_gpos] = ( r * i_trans +
774                                         (uint16_t)p_src1[i_gpos] *
775                                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
776                         p_dst[i_bpos] = ( r * i_trans +
777                                         (uint16_t)p_src1[i_gpos] *
778                                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
779                     }
780                 }
781             }
782         }
783     }
784
785 #undef MAX_TRANS
786 #undef TRANS_BITS
787
788     return;
789 }
790
791 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
792                             picture_t *p_dst_orig, picture_t *p_src,
793                             int i_x_offset, int i_y_offset,
794                             int i_width, int i_height, int i_alpha )
795 {
796     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
797     uint8_t *p_dst, *p_src1, *p_src2_y;
798     uint8_t *p_src2_u, *p_src2_v;
799     uint8_t *p_trans;
800     int i_x, i_y, i_pix_pitch, i_trans = 0;
801     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
802     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
803
804     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
805     {
806         i_l_offset = 0;
807         i_u_offset = 1;
808         i_v_offset = 3;
809     }
810     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
811     {
812         i_l_offset = 1;
813         i_u_offset = 0;
814         i_v_offset = 2;
815     }
816     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
817     {
818         i_l_offset = 0;
819         i_u_offset = 3;
820         i_v_offset = 1;
821     }
822
823     i_pix_pitch = 2;
824     i_dst_pitch = p_dst_pic->p->i_pitch;
825     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
826             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
827             p_dst_pic->p->i_pitch *
828             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
829
830     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
831     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
832                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
833                p_dst_orig->p->i_pitch *
834                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
835
836     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
837     p_src2_y = p_src->p[Y_PLANE].p_pixels +
838                p_filter->fmt_in.video.i_x_offset +
839                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
840     p_src2_u = p_src->p[U_PLANE].p_pixels +
841                p_filter->fmt_in.video.i_x_offset/2 +
842                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
843     p_src2_v = p_src->p[V_PLANE].p_pixels +
844                p_filter->fmt_in.video.i_x_offset/2 +
845                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
846
847     p_trans = p_src->p[A_PLANE].p_pixels +
848               p_filter->fmt_in.video.i_x_offset +
849               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
850
851     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
852
853 #define MAX_TRANS 255
854 #define TRANS_BITS  8
855
856     /* Draw until we reach the bottom of the subtitle */
857     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
858          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
859          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
860          p_src2_v += i_src2_pitch )
861     {
862         /* Draw until we reach the end of the line */
863         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
864         {
865             i_trans = ( p_trans[i_x] * i_alpha ) / 255;
866             if( !i_trans )
867             {
868                 /* Completely transparent. Don't change pixel */
869             }
870             else if( i_trans == MAX_TRANS )
871             {
872                 /* Completely opaque. Completely overwrite underlying pixel */
873                 p_dst[i_x * 2 + i_l_offset]     = p_src2_y[i_x];
874
875                 if( b_even )
876                 {
877                     if( p_trans[i_x+1] > 0xaa )
878                     {
879                         p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
880                         p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
881                     }
882                     else
883                     {
884                         p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
885                         p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
886                     }
887                 }
888             }
889             else
890             {
891                 /* Blending */
892                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)p_src2_y[i_x] * i_trans +
893                     (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
894                     >> TRANS_BITS;
895
896                 if( b_even )
897                 {
898                     uint16_t i_u = 0;
899                     uint16_t i_v = 0;
900                     if( p_trans[i_x+1] > 0xaa )
901                     {
902                         i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
903                         i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
904                     }
905                     else
906                     {
907                         i_u = p_src2_u[i_x];
908                         i_v = p_src2_v[i_x];
909                     }
910                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
911                         (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
912                         >> TRANS_BITS;
913                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
914                         (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
915                         >> TRANS_BITS;
916                 }
917             }
918         }
919     }
920
921 #undef MAX_TRANS
922 #undef TRANS_BITS
923
924     return;
925 }
926 /***********************************************************************
927  * I420, YV12
928  ***********************************************************************/
929 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
930                            picture_t *p_dst_orig, picture_t *p_src,
931                            int i_x_offset, int i_y_offset,
932                            int i_width, int i_height, int i_alpha )
933 {
934     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
935     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
936     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
937     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
938     int i_x, i_y;
939     vlc_bool_t b_even_scanline = i_y_offset % 2;
940
941     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
942     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
943               p_filter->fmt_out.video.i_x_offset +
944               p_dst->p[Y_PLANE].i_pitch *
945               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
946     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
947               p_filter->fmt_out.video.i_x_offset/2 +
948               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
949               p_dst->p[U_PLANE].i_pitch;
950     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
951               p_filter->fmt_out.video.i_x_offset/2 +
952               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
953               p_dst->p[V_PLANE].i_pitch;
954
955     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
956     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
957                p_filter->fmt_out.video.i_x_offset +
958                p_dst_orig->p[Y_PLANE].i_pitch *
959                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
960     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
961                p_filter->fmt_out.video.i_x_offset/2 +
962                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
963                p_dst_orig->p[U_PLANE].i_pitch;
964     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
965                p_filter->fmt_out.video.i_x_offset/2 +
966                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
967                p_dst_orig->p[V_PLANE].i_pitch;
968
969     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
970     p_src2_y = p_src->p[Y_PLANE].p_pixels +
971                p_filter->fmt_in.video.i_x_offset +
972                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
973     p_src2_u = p_src->p[U_PLANE].p_pixels +
974                p_filter->fmt_in.video.i_x_offset/2 +
975                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
976     p_src2_v = p_src->p[V_PLANE].p_pixels +
977                p_filter->fmt_in.video.i_x_offset/2 +
978                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
979
980 #define MAX_TRANS 255
981 #define TRANS_BITS  8
982
983     /* Draw until we reach the bottom of the subtitle */
984     for( i_y = 0; i_y < i_height; i_y++,
985          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
986          p_src2_y += i_src2_pitch )
987     {
988         if( b_even_scanline )
989         {
990             p_dst_u  += i_dst_pitch/2;
991             p_dst_v  += i_dst_pitch/2;
992             p_src1_u += i_src1_pitch/2;
993             p_src1_v += i_src1_pitch/2;
994         }
995         b_even_scanline = !b_even_scanline;
996
997         /* Draw until we reach the end of the line */
998         for( i_x = 0; i_x < i_width; i_x++ )
999         {
1000             if( i_alpha == MAX_TRANS )
1001             {
1002                 /* Completely opaque. Completely overwrite underlying pixel */
1003                 p_dst_y[i_x] = p_src2_y[i_x];
1004
1005                 if( b_even_scanline && i_x % 2 == 0 )
1006                 {
1007                     p_dst_u[i_x/2] = p_src2_u[i_x/2];
1008                     p_dst_v[i_x/2] = p_src2_v[i_x/2];
1009                 }
1010                 continue;
1011             }
1012
1013             /* Blending */
1014             p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1015                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_alpha) )
1016                 >> TRANS_BITS;
1017
1018             if( b_even_scanline && i_x % 2 == 0 )
1019             {
1020                 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x/2] * i_alpha +
1021                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_alpha) )
1022                 >> TRANS_BITS;
1023                 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x/2] * i_alpha +
1024                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_alpha) )
1025                 >> TRANS_BITS;
1026             }
1027         }
1028         if( i_y%2 == 1 )
1029         {
1030             p_src2_u += i_src2_pitch/2;
1031             p_src2_v += i_src2_pitch/2;
1032         }
1033     }
1034
1035 #undef MAX_TRANS
1036 #undef TRANS_BITS
1037
1038     return;
1039 }
1040 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
1041                                     picture_t *p_dst_orig, picture_t *p_src,
1042                                     int i_x_offset, int i_y_offset,
1043                                     int i_width, int i_height )
1044 {
1045     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1046     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
1047     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
1048     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
1049     int i_y;
1050     vlc_bool_t b_even_scanline = i_y_offset % 2;
1051
1052     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1053     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1054               p_filter->fmt_out.video.i_x_offset +
1055               p_dst->p[Y_PLANE].i_pitch *
1056               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1057     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1058               p_filter->fmt_out.video.i_x_offset/2 +
1059               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1060               p_dst->p[U_PLANE].i_pitch;
1061     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1062               p_filter->fmt_out.video.i_x_offset/2 +
1063               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1064               p_dst->p[V_PLANE].i_pitch;
1065
1066     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1067     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1068                p_filter->fmt_out.video.i_x_offset +
1069                p_dst_orig->p[Y_PLANE].i_pitch *
1070                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1071     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1072                p_filter->fmt_out.video.i_x_offset/2 +
1073                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1074                p_dst_orig->p[U_PLANE].i_pitch;
1075     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1076                p_filter->fmt_out.video.i_x_offset/2 +
1077                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1078                p_dst_orig->p[V_PLANE].i_pitch;
1079
1080     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1081     p_src2_y = p_src->p[Y_PLANE].p_pixels +
1082                p_filter->fmt_in.video.i_x_offset +
1083                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1084     p_src2_u = p_src->p[U_PLANE].p_pixels +
1085                p_filter->fmt_in.video.i_x_offset/2 +
1086                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1087     p_src2_v = p_src->p[V_PLANE].p_pixels +
1088                p_filter->fmt_in.video.i_x_offset/2 +
1089                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1090
1091     i_width &= ~1;
1092
1093     /* Draw until we reach the bottom of the subtitle */
1094     for( i_y = 0; i_y < i_height; i_y++,
1095          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1096          p_src2_y += i_src2_pitch )
1097     {
1098         /* Completely opaque. Completely overwrite underlying pixel */
1099         p_filter->p_libvlc->pf_memcpy( p_dst_y, p_src2_y, i_width );
1100         if( b_even_scanline )
1101         {
1102             p_dst_u  += i_dst_pitch/2;
1103             p_dst_v  += i_dst_pitch/2;
1104             p_src1_u += i_src1_pitch/2;
1105             p_src1_v += i_src1_pitch/2;
1106         }
1107         else
1108         {
1109             p_filter->p_libvlc->pf_memcpy( p_dst_u, p_src2_u, i_width/2 );
1110             p_filter->p_libvlc->pf_memcpy( p_dst_v, p_src2_v, i_width/2 );
1111         }
1112         b_even_scanline = !b_even_scanline;
1113         if( i_y%2 == 1 )
1114         {
1115             p_src2_u += i_src2_pitch/2;
1116             p_src2_v += i_src2_pitch/2;
1117         }
1118     }
1119
1120     return;
1121 }
1122
1123 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1124                           picture_t *p_dst_orig, picture_t *p_src,
1125                           int i_x_offset, int i_y_offset,
1126                           int i_width, int i_height, int i_alpha )
1127 {
1128     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1129     uint8_t *p_dst, *p_src1, *p_src2_y;
1130     uint8_t *p_src2_u, *p_src2_v;
1131     int i_x, i_y, i_pix_pitch;
1132     int r, g, b;
1133
1134     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1135     i_dst_pitch = p_dst_pic->p->i_pitch;
1136     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1137             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1138             p_dst_pic->p->i_pitch *
1139             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1140
1141     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1142     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1143                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1144                p_dst_orig->p->i_pitch *
1145                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1146
1147     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1148     p_src2_y = p_src->p[Y_PLANE].p_pixels +
1149                p_filter->fmt_in.video.i_x_offset +
1150                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1151     p_src2_u = p_src->p[U_PLANE].p_pixels +
1152                p_filter->fmt_in.video.i_x_offset/2 +
1153                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1154     p_src2_v = p_src->p[V_PLANE].p_pixels +
1155                p_filter->fmt_in.video.i_x_offset/2 +
1156                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1157
1158 #define MAX_TRANS 255
1159 #define TRANS_BITS  8
1160
1161     /* Draw until we reach the bottom of the subtitle */
1162     for( i_y = 0; i_y < i_height; i_y++,
1163          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1164          p_src2_y += i_src2_pitch )
1165     {
1166         /* Draw until we reach the end of the line */
1167         for( i_x = 0; i_x < i_width; i_x++ )
1168         {
1169             if( i_alpha == MAX_TRANS )
1170             {
1171                 /* Completely opaque. Completely overwrite underlying pixel */
1172                 yuv_to_rgb( &r, &g, &b,
1173                             p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1174
1175     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1176                 continue;
1177             }
1178
1179             /* Blending */
1180             /* FIXME: do the blending */
1181             yuv_to_rgb( &r, &g, &b,
1182                         p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1183
1184     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1185         }
1186         if( i_y%2 == 1 )
1187         {
1188             p_src2_u += i_src2_pitch/2;
1189             p_src2_v += i_src2_pitch/2;
1190         }
1191     }
1192
1193 #undef MAX_TRANS
1194 #undef TRANS_BITS
1195
1196     return;
1197 }
1198
1199 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1200                           picture_t *p_dst_orig, picture_t *p_src,
1201                           int i_x_offset, int i_y_offset,
1202                           int i_width, int i_height, int i_alpha )
1203 {
1204     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1205     uint8_t *p_dst, *p_src1, *p_src2_y;
1206     uint8_t *p_src2_u, *p_src2_v;
1207     int i_x, i_y, i_pix_pitch;
1208     int r, g, b;
1209
1210     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1211     i_dst_pitch = p_dst_pic->p->i_pitch;
1212     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1213             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1214             p_dst_pic->p->i_pitch *
1215             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1216
1217     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1218     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1219                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1220                p_dst_orig->p->i_pitch *
1221                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1222
1223     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1224     p_src2_y = p_src->p[Y_PLANE].p_pixels +
1225                p_filter->fmt_in.video.i_x_offset +
1226                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1227     p_src2_u = p_src->p[U_PLANE].p_pixels +
1228                p_filter->fmt_in.video.i_x_offset/2 +
1229                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1230     p_src2_v = p_src->p[V_PLANE].p_pixels +
1231                p_filter->fmt_in.video.i_x_offset/2 +
1232                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1233
1234 #define MAX_TRANS 255
1235 #define TRANS_BITS  8
1236
1237     /* Draw until we reach the bottom of the subtitle */
1238     for( i_y = 0; i_y < i_height; i_y++,
1239          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1240          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1241          p_src2_v += i_src2_pitch )
1242     {
1243         /* Draw until we reach the end of the line */
1244         for( i_x = 0; i_x < i_width; i_x++ )
1245         {
1246             if( i_alpha == MAX_TRANS )
1247             {
1248                 /* Completely opaque. Completely overwrite underlying pixel */
1249                 yuv_to_rgb( &r, &g, &b,
1250                             p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1251
1252                 p_dst[i_x * i_pix_pitch]     = r;
1253                 p_dst[i_x * i_pix_pitch + 1] = g;
1254                 p_dst[i_x * i_pix_pitch + 2] = b;
1255                 continue;
1256             }
1257
1258             /* Blending */
1259             yuv_to_rgb( &r, &g, &b,
1260                         p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1261
1262             p_dst[i_x * i_pix_pitch]     = ( r * i_alpha +
1263                 (uint16_t)p_src1[i_x * i_pix_pitch] *
1264                 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1265             p_dst[i_x * i_pix_pitch + 1] = ( g * i_alpha +
1266                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1267                 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1268             p_dst[i_x * i_pix_pitch + 2] = ( b * i_alpha +
1269                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1270                 (MAX_TRANS - i_alpha) ) >> TRANS_BITS;
1271         }
1272         if( i_y%2 == 1 )
1273         {
1274             p_src2_u += i_src2_pitch/2;
1275             p_src2_v += i_src2_pitch/2;
1276         }
1277     }
1278
1279 #undef MAX_TRANS
1280 #undef TRANS_BITS
1281
1282     return;
1283 }
1284
1285 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1286                                 picture_t *p_dst_orig, picture_t *p_src,
1287                                 int i_x_offset, int i_y_offset,
1288                                 int i_width, int i_height, int i_alpha )
1289 {
1290     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1291     uint8_t *p_dst, *p_src1, *p_src2_y;
1292     uint8_t *p_src2_u, *p_src2_v;
1293     int i_x, i_y, i_pix_pitch;
1294     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1295     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1296
1297     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1298     {
1299         i_l_offset = 0;
1300         i_u_offset = 1;
1301         i_v_offset = 3;
1302     }
1303     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1304     {
1305         i_l_offset = 1;
1306         i_u_offset = 0;
1307         i_v_offset = 2;
1308     }
1309     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1310     {
1311         i_l_offset = 0;
1312         i_u_offset = 3;
1313         i_v_offset = 1;
1314     }
1315
1316     i_pix_pitch = 2;
1317     i_dst_pitch = p_dst_pic->p->i_pitch;
1318     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1319             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1320             p_dst_pic->p->i_pitch *
1321             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1322
1323     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1324     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1325                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1326                p_dst_orig->p->i_pitch *
1327                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1328
1329     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1330     p_src2_y = p_src->p[Y_PLANE].p_pixels +
1331                p_filter->fmt_in.video.i_x_offset +
1332                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1333     p_src2_u = p_src->p[U_PLANE].p_pixels +
1334                p_filter->fmt_in.video.i_x_offset/2 +
1335                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1336     p_src2_v = p_src->p[V_PLANE].p_pixels +
1337                p_filter->fmt_in.video.i_x_offset/2 +
1338                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1339
1340     i_width &= ~1; /* Needs to be a multiple of 2 */
1341
1342 #define MAX_TRANS 255
1343 #define TRANS_BITS  8
1344
1345     /* Draw until we reach the bottom of the subtitle */
1346     for( i_y = 0; i_y < i_height; i_y++,
1347          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1348          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1349          p_src2_v += i_src2_pitch )
1350     {
1351         /* Draw until we reach the end of the line */
1352         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1353         {
1354             if( i_alpha == MAX_TRANS )
1355             {
1356                 /* Completely opaque. Completely overwrite underlying pixel */
1357                 p_dst[i_x * 2 + i_l_offset]     = p_src2_y[i_x];
1358
1359                 if( b_even )
1360                 {
1361                     p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x/2];
1362                     p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x/2];
1363                 }
1364             }
1365             else
1366             {
1367                 /* Blending */
1368                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)p_src2_y[i_x] * i_alpha +
1369                     (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_alpha) )
1370                     >> TRANS_BITS;
1371
1372                 if( b_even )
1373                 {
1374                     uint16_t i_u = p_src2_u[i_x/2];
1375                     uint16_t i_v = p_src2_v[i_x/2];
1376                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_alpha +
1377                         (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_alpha) )
1378                         >> TRANS_BITS;
1379                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_alpha +
1380                         (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_alpha) )
1381                         >> TRANS_BITS;
1382                 }
1383             }
1384         }
1385         if( i_y%2 == 1 )
1386         {
1387             p_src2_u += i_src2_pitch/2;
1388             p_src2_v += i_src2_pitch/2;
1389         }
1390     }
1391
1392 #undef MAX_TRANS
1393 #undef TRANS_BITS
1394
1395     return;
1396 }
1397
1398 /***********************************************************************
1399  * YUVP
1400  ***********************************************************************/
1401 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1402                           picture_t *p_dst_orig, picture_t *p_src,
1403                           int i_x_offset, int i_y_offset,
1404                           int i_width, int i_height, int i_alpha )
1405 {
1406     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1407     uint8_t *p_src1_y, *p_src2, *p_dst_y;
1408     uint8_t *p_src1_u, *p_dst_u;
1409     uint8_t *p_src1_v, *p_dst_v;
1410     int i_x, i_y, i_trans;
1411     vlc_bool_t b_even_scanline = i_y_offset % 2;
1412
1413     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1414     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1415               p_filter->fmt_out.video.i_x_offset +
1416               p_dst->p[Y_PLANE].i_pitch *
1417               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1418     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1419               p_filter->fmt_out.video.i_x_offset/2 +
1420               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1421               p_dst->p[U_PLANE].i_pitch;
1422     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1423               p_filter->fmt_out.video.i_x_offset/2 +
1424               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1425               p_dst->p[V_PLANE].i_pitch;
1426
1427     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1428     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1429                p_filter->fmt_out.video.i_x_offset +
1430                p_dst_orig->p[Y_PLANE].i_pitch *
1431                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1432     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1433                p_filter->fmt_out.video.i_x_offset/2 +
1434                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1435                p_dst_orig->p[U_PLANE].i_pitch;
1436     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1437                p_filter->fmt_out.video.i_x_offset/2 +
1438                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1439                p_dst_orig->p[V_PLANE].i_pitch;
1440
1441     i_src2_pitch = p_src->p->i_pitch;
1442     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1443              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1444
1445 #define MAX_TRANS 255
1446 #define TRANS_BITS  8
1447 #define p_trans p_src2
1448 #define p_pal p_filter->fmt_in.video.p_palette->palette
1449
1450     /* Draw until we reach the bottom of the subtitle */
1451     for( i_y = 0; i_y < i_height; i_y++,
1452          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1453          p_src2 += i_src2_pitch,
1454          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1455          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1456          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1457          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1458     {
1459         b_even_scanline = !b_even_scanline;
1460
1461         /* Draw until we reach the end of the line */
1462         for( i_x = 0; i_x < i_width; i_x++ )
1463         {
1464             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1465             if( !i_trans )
1466             {
1467                 /* Completely transparent. Don't change pixel */
1468                 continue;
1469             }
1470             else if( i_trans == MAX_TRANS )
1471             {
1472                 /* Completely opaque. Completely overwrite underlying pixel */
1473                 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
1474
1475                 if( b_even_scanline && i_x % 2 == 0 )
1476                 {
1477                     p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
1478                     p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
1479                 }
1480                 continue;
1481             }
1482
1483             /* Blending */
1484             p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
1485                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1486                 >> TRANS_BITS;
1487
1488             if( b_even_scanline && i_x % 2 == 0 )
1489             {
1490                 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
1491                     (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1492                     >> TRANS_BITS;
1493                 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
1494                     (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1495                     >> TRANS_BITS;
1496             }
1497         }
1498     }
1499
1500 #undef MAX_TRANS
1501 #undef TRANS_BITS
1502 #undef p_trans
1503 #undef p_pal
1504
1505     return;
1506 }
1507
1508 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1509                                picture_t *p_dst_orig, picture_t *p_src,
1510                                int i_x_offset, int i_y_offset,
1511                                int i_width, int i_height, int i_alpha )
1512 {
1513     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1514     uint8_t *p_src1, *p_src2, *p_dst;
1515     int i_x, i_y, i_pix_pitch, i_trans;
1516     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1517     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1518
1519     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1520     {
1521         i_l_offset = 0;
1522         i_u_offset = 1;
1523         i_v_offset = 3;
1524     }
1525     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1526     {
1527         i_l_offset = 1;
1528         i_u_offset = 0;
1529         i_v_offset = 2;
1530     }
1531     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1532     {
1533         i_l_offset = 0;
1534         i_u_offset = 3;
1535         i_v_offset = 1;
1536     }
1537
1538     i_pix_pitch = 2;
1539     i_dst_pitch = p_dst_pic->p->i_pitch;
1540     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1541             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1542             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1543
1544     i_src1_pitch = p_dst_orig->p->i_pitch;
1545     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1546              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1547              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1548
1549     i_src2_pitch = p_src->p->i_pitch;
1550     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1551              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1552
1553     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1554
1555 #define MAX_TRANS 255
1556 #define TRANS_BITS  8
1557 #define p_trans p_src2
1558 #define p_pal p_filter->fmt_in.video.p_palette->palette
1559
1560     /* Draw until we reach the bottom of the subtitle */
1561     for( i_y = 0; i_y < i_height; i_y++,
1562          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1563     {
1564         /* Draw until we reach the end of the line */
1565         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1566         {
1567             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1568             if( !i_trans )
1569             {
1570                 /* Completely transparent. Don't change pixel */
1571             }
1572             else if( i_trans == MAX_TRANS )
1573             {
1574                 /* Completely opaque. Completely overwrite underlying pixel */
1575                 p_dst[i_x * 2 + i_l_offset]     = p_pal[p_src2[i_x]][0];
1576
1577                 if( b_even )
1578                 {
1579                     if( p_trans[i_x+1] > 0xaa )
1580                     {
1581                         p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1582                         p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1583                     }
1584                     else
1585                     {
1586                         p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
1587                         p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
1588                     }
1589                 }
1590             }
1591             else
1592             {
1593                 /* Blending */
1594                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)p_pal[p_src2[i_x]][0] *
1595                     i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
1596                     (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1597
1598                 if( b_even )
1599                 {
1600                     uint16_t i_u = 0;
1601                     uint16_t i_v = 0;
1602                     if( p_trans[i_x+1] > 0xaa )
1603                     {
1604                         i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1605                         i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1606                     }
1607                     else
1608                     {
1609                         i_u = p_pal[p_src2[i_x]][1];
1610                         i_v = p_pal[p_src2[i_x]][2];
1611                     }
1612
1613                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
1614                         i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
1615                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1616                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
1617                         i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
1618                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1619                 }
1620             }
1621         }
1622     }
1623
1624 #undef MAX_TRANS
1625 #undef TRANS_BITS
1626 #undef p_trans
1627 #undef p_pal
1628
1629     return;
1630 }
1631
1632 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1633                         picture_t *p_dst_orig, picture_t *p_src,
1634                         int i_x_offset, int i_y_offset,
1635                         int i_width, int i_height, int i_alpha )
1636 {
1637     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1638     uint8_t *p_src1, *p_src2, *p_dst;
1639     int i_x, i_y, i_pix_pitch, i_trans;
1640     int r, g, b;
1641     video_palette_t rgbpalette;
1642
1643     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1644     i_dst_pitch = p_dst_pic->p->i_pitch;
1645     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1646             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1647             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1648
1649     i_src1_pitch = p_dst_orig->p->i_pitch;
1650     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1651              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1652              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1653
1654     i_src2_pitch = p_src->p->i_pitch;
1655     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1656              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1657
1658 #define MAX_TRANS 255
1659 #define TRANS_BITS  8
1660 #define p_trans p_src2
1661 #define p_pal p_filter->fmt_in.video.p_palette->palette
1662 #define rgbpal rgbpalette.palette
1663
1664     /* Convert palette first */
1665     for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1666          i_y < 256; i_y++ )
1667     {
1668         yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1669
1670         if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1671         {
1672             *(uint16_t *)rgbpal[i_y] =
1673                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1674         }
1675         else
1676         {
1677             rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1678         }
1679     }
1680
1681     /* Draw until we reach the bottom of the subtitle */
1682     for( i_y = 0; i_y < i_height; i_y++,
1683          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1684     {
1685         /* Draw until we reach the end of the line */
1686         for( i_x = 0; i_x < i_width; i_x++ )
1687         {
1688             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1689             if( !i_trans )
1690             {
1691                 /* Completely transparent. Don't change pixel */
1692                 continue;
1693             }
1694             else if( i_trans == MAX_TRANS ||
1695                      p_filter->fmt_out.video.i_chroma ==
1696                      VLC_FOURCC('R','V','1','6') )
1697             {
1698                 /* Completely opaque. Completely overwrite underlying pixel */
1699                 p_dst[i_x * i_pix_pitch]     = rgbpal[p_src2[i_x]][0];
1700                 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1701                 if( p_filter->fmt_out.video.i_chroma !=
1702                     VLC_FOURCC('R','V','1','6') )
1703                 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1704                 continue;
1705             }
1706
1707             /* Blending */
1708             p_dst[i_x * i_pix_pitch]     = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1709                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1710                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1711             p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1712                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1713                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1714             p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1715                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1716                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1717         }
1718     }
1719
1720 #undef MAX_TRANS
1721 #undef TRANS_BITS
1722 #undef p_trans
1723 #undef p_pal
1724 #undef rgbpal
1725
1726     return;
1727 }
1728
1729 /***********************************************************************
1730  * RGBA
1731  ***********************************************************************/
1732 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1733                            picture_t *p_dst_orig, picture_t *p_src,
1734                            int i_x_offset, int i_y_offset,
1735                            int i_width, int i_height, int i_alpha )
1736 {
1737     int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1738     uint8_t *p_src1_y, *p_dst_y;
1739     uint8_t *p_src1_u, *p_dst_u;
1740     uint8_t *p_src1_v, *p_dst_v;
1741     uint8_t *p_src2;
1742     int i_x, i_y, i_trans;
1743     uint8_t y, u, v;
1744
1745     vlc_bool_t b_even_scanline = i_y_offset % 2;
1746
1747     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1748     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1749               p_filter->fmt_out.video.i_x_offset +
1750               p_dst->p[Y_PLANE].i_pitch *
1751               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1752     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1753               p_filter->fmt_out.video.i_x_offset/2 +
1754               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1755               p_dst->p[U_PLANE].i_pitch;
1756     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1757               p_filter->fmt_out.video.i_x_offset/2 +
1758               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1759               p_dst->p[V_PLANE].i_pitch;
1760
1761     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1762     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1763                p_filter->fmt_out.video.i_x_offset +
1764                p_dst_orig->p[Y_PLANE].i_pitch *
1765                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1766     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1767                p_filter->fmt_out.video.i_x_offset/2 +
1768                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1769                p_dst_orig->p[U_PLANE].i_pitch;
1770     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1771                p_filter->fmt_out.video.i_x_offset/2 +
1772                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1773                p_dst_orig->p[V_PLANE].i_pitch;
1774
1775     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1776     i_src2_pitch = p_src->p->i_pitch;
1777     p_src2 = p_src->p->p_pixels +
1778              p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1779              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1780
1781
1782 #define MAX_TRANS 255
1783 #define TRANS_BITS  8
1784
1785     /* Draw until we reach the bottom of the subtitle */
1786     for( i_y = 0; i_y < i_height; i_y++,
1787          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1788          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1789          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1790          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1791          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1792          p_src2 += i_src2_pitch )
1793     {
1794         b_even_scanline = !b_even_scanline;
1795
1796         /* Draw until we reach the end of the line */
1797         for( i_x = 0; i_x < i_width; i_x++ )
1798         {
1799 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1800 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1801 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1802             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1803             if( !i_trans )
1804             {
1805                 /* Completely transparent. Don't change pixel */
1806                 continue;
1807             }
1808             else if( i_trans == MAX_TRANS )
1809             {
1810                 /* Completely opaque. Completely overwrite underlying pixel */
1811                 rgb_to_yuv( &y, &u, &v, R, G, B );
1812                 p_dst_y[i_x] = y;
1813
1814                 if( b_even_scanline && i_x % 2 == 0 )
1815                 {
1816                     p_dst_u[i_x/2] = u;
1817                     p_dst_v[i_x/2] = v;
1818                 }
1819                 continue;
1820             }
1821
1822             /* Blending */
1823             rgb_to_yuv( &y, &u, &v, R, G, B );
1824             p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1825                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1826                 >> TRANS_BITS;
1827
1828             if( b_even_scanline && i_x % 2 == 0 )
1829             {
1830                 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1831                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1832                 >> TRANS_BITS;
1833                 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1834                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1835                 >> TRANS_BITS;
1836             }
1837 #undef      R
1838 #undef      G
1839 #undef      B
1840         }
1841     }
1842
1843 #undef MAX_TRANS
1844 #undef TRANS_BITS
1845
1846     return;
1847 }
1848
1849 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1850                           picture_t *p_dst_orig, picture_t *p_src,
1851                           int i_x_offset, int i_y_offset,
1852                           int i_width, int i_height, int i_alpha )
1853 {
1854     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1855     uint8_t *p_dst, *p_src1, *p_src2;
1856     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1857
1858     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1859     i_dst_pitch = p_dst_pic->p->i_pitch;
1860     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1861             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1862             p_dst_pic->p->i_pitch *
1863             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1864
1865     i_src1_pitch = p_dst_orig->p->i_pitch;
1866     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1867              p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1868              p_dst_orig->p->i_pitch *
1869              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1870
1871     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1872     i_src2_pitch = p_src->p->i_pitch;
1873     p_src2 = p_src->p->p_pixels +
1874              p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1875              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1876
1877 #define MAX_TRANS 255
1878 #define TRANS_BITS  8
1879
1880     /* Draw until we reach the bottom of the subtitle */
1881     for( i_y = 0; i_y < i_height; i_y++,
1882          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1883     {
1884         /* Draw until we reach the end of the line */
1885         for( i_x = 0; i_x < i_width; i_x++ )
1886         {
1887 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1888 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1889 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1890             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1891             if( !i_trans )
1892             {
1893                 /* Completely transparent. Don't change pixel */
1894                 continue;
1895             }
1896             else if( i_trans == MAX_TRANS )
1897             {
1898                 /* Completely opaque. Completely overwrite underlying pixel */
1899                 p_dst[i_x * i_pix_pitch + 0] = R;
1900                 p_dst[i_x * i_pix_pitch + 1] = G;
1901                 p_dst[i_x * i_pix_pitch + 2] = B;
1902                 continue;
1903             }
1904
1905             /* Blending */
1906             p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1907                 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1908                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1909             p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1910                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1911                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1912             p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1913                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1914                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1915 #undef      R
1916 #undef      G
1917 #undef      B
1918         }
1919     }
1920
1921 #undef MAX_TRANS
1922 #undef TRANS_BITS
1923
1924     return;
1925 }
1926
1927 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1928                           picture_t *p_dst_orig, picture_t *p_src,
1929                           int i_x_offset, int i_y_offset,
1930                           int i_width, int i_height, int i_alpha )
1931 {
1932     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1933     uint8_t *p_dst, *p_src1, *p_src2;
1934     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1935     uint16_t i_pix;
1936
1937     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1938     i_dst_pitch = p_dst_pic->p->i_pitch;
1939     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1940             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1941             p_dst_pic->p->i_pitch *
1942             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1943
1944     i_src1_pitch = p_dst_orig->p->i_pitch;
1945     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1946              p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1947              p_dst_orig->p->i_pitch *
1948              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1949
1950     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1951     i_src2_pitch = p_src->p->i_pitch;
1952     p_src2 = p_src->p->p_pixels +
1953              p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1954              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1955
1956 #define MAX_TRANS 255
1957 #define TRANS_BITS  8
1958
1959     /* Draw until we reach the bottom of the subtitle */
1960     for( i_y = 0; i_y < i_height; i_y++,
1961          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1962     {
1963         /* Draw until we reach the end of the line */
1964         for( i_x = 0; i_x < i_width; i_x++ )
1965         {
1966 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1967 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1968 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1969             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1970             if( !i_trans )
1971             {
1972                 /* Completely transparent. Don't change pixel */
1973                 continue;
1974             }
1975             else if( i_trans == MAX_TRANS )
1976             {
1977                 /* Completely opaque. Completely overwrite underlying pixel */
1978                 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1979                 continue;
1980             }
1981
1982             /* Blending */
1983             i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1984             *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1985                 ( ( ( (R >> 3)*i_trans
1986                     + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1987                     >> TRANS_BITS ) << 11 )
1988               | ( ( ( (G >> 2)*i_trans
1989                     + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1990                     >> TRANS_BITS ) << 5  )
1991               | ( ( ( (B >> 3)*i_trans
1992                     + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
1993                     >> TRANS_BITS ) );
1994 #undef      R
1995 #undef      G
1996 #undef      B
1997         }
1998     }
1999
2000 #undef MAX_TRANS
2001 #undef TRANS_BITS
2002
2003     return;
2004 }
2005
2006 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
2007                                 picture_t *p_dst_orig, picture_t *p_src,
2008                                 int i_x_offset, int i_y_offset,
2009                                 int i_width, int i_height, int i_alpha )
2010 {
2011     int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
2012     uint8_t *p_dst, *p_src1, *p_src2;
2013     uint8_t *p_trans;
2014     int i_x, i_y, i_pix_pitch, i_trans;
2015     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
2016     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
2017     uint8_t y, u, v;
2018
2019     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
2020     {
2021         i_l_offset = 0;
2022         i_u_offset = 1;
2023         i_v_offset = 3;
2024     }
2025     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
2026     {
2027         i_l_offset = 1;
2028         i_u_offset = 0;
2029         i_v_offset = 2;
2030     }
2031     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
2032     {
2033         i_l_offset = 0;
2034         i_u_offset = 3;
2035         i_v_offset = 1;
2036     }
2037
2038     i_pix_pitch = 2;
2039     i_dst_pitch = p_dst_pic->p->i_pitch;
2040     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
2041             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2042             p_dst_pic->p->i_pitch *
2043             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2044
2045     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
2046     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
2047                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
2048                p_dst_orig->p->i_pitch *
2049                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
2050
2051     i_src_pix_pitch = p_src->p->i_pixel_pitch;
2052     i_src2_pitch = p_src->p->i_pitch;
2053     p_src2 = p_src->p->p_pixels +
2054              p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
2055              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
2056
2057     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
2058
2059 #define MAX_TRANS 255
2060 #define TRANS_BITS  8
2061
2062     /* Draw until we reach the bottom of the subtitle */
2063     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
2064          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
2065          p_src2 += i_src2_pitch )
2066     {
2067         /* Draw until we reach the end of the line */
2068         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
2069         {
2070 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
2071 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
2072 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
2073             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
2074             if( !i_trans )
2075             {
2076                 /* Completely transparent. Don't change pixel */
2077             }
2078             else if( i_trans == MAX_TRANS )
2079             {
2080                 /* Completely opaque. Completely overwrite underlying pixel */
2081                 rgb_to_yuv( &y, &u, &v, R, G, B );
2082                 p_dst[i_x * 2 + i_l_offset] = y;
2083
2084                 if( b_even )
2085                 {
2086                     p_dst[i_x * 2 + i_u_offset] = u;
2087                     p_dst[i_x * 2 + i_v_offset] = v;
2088                 }
2089             }
2090             else
2091             {
2092                 /* Blending */
2093                 rgb_to_yuv( &y, &u, &v, R, G, B );
2094                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)y * i_trans +
2095                     (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
2096                     >> TRANS_BITS;
2097
2098                 if( b_even )
2099                 {
2100                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)u * i_trans +
2101                         (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
2102                         >> TRANS_BITS;
2103                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)v * i_trans +
2104                         (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
2105                         >> TRANS_BITS;
2106                 }
2107             }
2108         }
2109     }
2110
2111 #undef MAX_TRANS
2112 #undef TRANS_BITS
2113
2114     return;
2115 }