]> git.sesse.net Git - vlc/blob - modules/video_filter/blend.c
Remove useless empty line.
[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     return VLC_SUCCESS;
145 }
146
147 /*****************************************************************************
148  * CloseFilter: clean up the filter
149  *****************************************************************************/
150 static void CloseFilter( vlc_object_t *p_this )
151 {
152     filter_t *p_filter = (filter_t*)p_this;
153     filter_sys_t *p_sys = p_filter->p_sys;
154
155     free( p_sys );
156 }
157
158 /****************************************************************************
159  * Blend: the whole thing
160  ****************************************************************************
161  * This function is called just after the thread is launched.
162  ****************************************************************************/
163 static void Blend( filter_t *p_filter, picture_t *p_dst,
164                    picture_t *p_dst_orig, picture_t *p_src,
165                    int i_x_offset, int i_y_offset, int i_alpha )
166 {
167     int i_width, i_height;
168
169     if( i_alpha == 0 ) return;
170
171     i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
172                     (int)p_filter->fmt_in.video.i_visible_width);
173
174     i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
175                      (int)p_filter->fmt_in.video.i_visible_height);
176
177     if( i_width <= 0 || i_height <= 0 ) return;
178
179 #if 0
180     printf( "chroma: %4.4s -> %4.4s\n",
181              (char *)&p_filter->fmt_in.video.i_chroma,
182              (char *)&p_filter->fmt_out.video.i_chroma );
183 #endif
184
185     switch( p_filter->fmt_in.video.i_chroma )
186     {
187         case VLC_FOURCC('Y','U','V','A'):
188             switch( p_filter->fmt_out.video.i_chroma )
189             {
190                 case VLC_FOURCC('I','4','2','0'):
191                 case VLC_FOURCC('Y','V','1','2'):
192                     BlendI420( p_filter, p_dst, p_dst_orig, p_src,
193                                i_x_offset, i_y_offset,
194                                i_width, i_height, i_alpha );
195                     return;
196                 case VLC_FOURCC('Y','U','Y','2'):
197                 case VLC_FOURCC('U','Y','V','Y'):
198                 case VLC_FOURCC('Y','V','Y','U'):
199                     BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
200                                     i_x_offset, i_y_offset,
201                                     i_width, i_height, i_alpha );
202                     return;
203                 case VLC_FOURCC('R','V','1','6'):
204                     BlendR16( p_filter, p_dst, p_dst_orig, p_src,
205                               i_x_offset, i_y_offset,
206                               i_width, i_height, i_alpha );
207                     return;
208                 case VLC_FOURCC('R','V','2','4'):
209                 case VLC_FOURCC('R','V','3','2'):
210                     BlendR24( p_filter, p_dst, p_dst_orig, p_src,
211                               i_x_offset, i_y_offset,
212                               i_width, i_height, i_alpha );
213                     return;
214             }
215         case VLC_FOURCC('Y','U','V','P'):
216             switch( p_filter->fmt_out.video.i_chroma )
217             {
218                 case VLC_FOURCC('I','4','2','0'):
219                 case VLC_FOURCC('Y','V','1','2'):
220                     BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
221                                   i_x_offset, i_y_offset,
222                                   i_width, i_height, i_alpha );
223                     return;
224                 case VLC_FOURCC('Y','U','Y','2'):
225                 case VLC_FOURCC('U','Y','V','Y'):
226                 case VLC_FOURCC('Y','V','Y','U'):
227                     BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
228                                        i_x_offset, i_y_offset,
229                                        i_width, i_height, i_alpha );
230                     return;
231                 case VLC_FOURCC('R','V','1','6'):
232                 case VLC_FOURCC('R','V','2','4'):
233                 case VLC_FOURCC('R','V','3','2'):
234                     BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
235                                 i_x_offset, i_y_offset,
236                                 i_width, i_height, i_alpha );
237                     return;
238             }
239         case VLC_FOURCC('Y','V','1','2'):
240         case VLC_FOURCC('I','4','2','0'):
241             switch( p_filter->fmt_out.video.i_chroma )
242             {
243                 case VLC_FOURCC('I','4','2','0'):
244                 case VLC_FOURCC('Y','V','1','2'):
245                     if( i_alpha == 0xff )
246                         BlendI420I420_no_alpha(
247                                    p_filter, p_dst, p_dst_orig, p_src,
248                                    i_x_offset, i_y_offset,
249                                    i_width, i_height );
250                     else
251                         BlendI420I420( p_filter, p_dst, p_dst_orig, p_src,
252                                        i_x_offset, i_y_offset,
253                                        i_width, i_height, i_alpha );
254                     return;
255                 case VLC_FOURCC('Y','U','Y','2'):
256                 case VLC_FOURCC('U','Y','V','Y'):
257                 case VLC_FOURCC('Y','V','Y','U'):
258                     BlendI420YUVPacked( p_filter, p_dst, p_dst_orig, p_src,
259                                         i_x_offset, i_y_offset,
260                                         i_width, i_height, i_alpha );
261                     return;
262                 case VLC_FOURCC('R','V','1','6'):
263                     BlendI420R16( p_filter, p_dst, p_dst_orig, p_src,
264                                   i_x_offset, i_y_offset,
265                                   i_width, i_height, i_alpha );
266                     return;
267                 case VLC_FOURCC('R','V','2','4'):
268                 case VLC_FOURCC('R','V','3','2'):
269                     BlendI420R24( p_filter, p_dst, p_dst_orig, p_src,
270                                   i_x_offset, i_y_offset,
271                                   i_width, i_height, i_alpha );
272                     return;
273             }
274         case VLC_FOURCC('R','G','B','A'):
275             switch( p_filter->fmt_out.video.i_chroma )
276             {
277                 case VLC_FOURCC('I','4','2','0'):
278                 case VLC_FOURCC('Y','V','1','2'):
279                     BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
280                                    i_x_offset, i_y_offset,
281                                    i_width, i_height, i_alpha );
282                     return;
283                 case VLC_FOURCC('Y','U','Y','2'):
284                 case VLC_FOURCC('U','Y','V','Y'):
285                 case VLC_FOURCC('Y','V','Y','U'):
286                     BlendRGBAYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
287                                         i_x_offset, i_y_offset,
288                                         i_width, i_height, i_alpha );
289                     return;
290                 case VLC_FOURCC('R','V','2','4'):
291                 case VLC_FOURCC('R','V','3','2'):
292                     BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
293                                   i_x_offset, i_y_offset,
294                                   i_width, i_height, i_alpha );
295                     return;
296                 case VLC_FOURCC('R','V','1','6'):
297                     BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
298                                   i_x_offset, i_y_offset,
299                                   i_width, i_height, i_alpha );
300                     return;
301             }
302     }
303
304     msg_Dbg( p_filter, "no matching alpha blending routine "
305              "(chroma: %4.4s -> %4.4s)",
306              (char *)&p_filter->fmt_in.video.i_chroma,
307              (char *)&p_filter->fmt_out.video.i_chroma );
308 }
309
310 /***********************************************************************
311  * Utils
312  ***********************************************************************/
313 static inline void yuv_to_rgb( int *r, int *g, int *b,
314                                uint8_t y1, uint8_t u1, uint8_t v1 )
315 {
316     /* macros used for YUV pixel conversions */
317 #   define SCALEBITS 10
318 #   define ONE_HALF  (1 << (SCALEBITS - 1))
319 #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
320 #   define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
321
322     int y, cb, cr, r_add, g_add, b_add;
323
324     cb = u1 - 128;
325     cr = v1 - 128;
326     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
327     g_add = - FIX(0.34414*255.0/224.0) * cb
328             - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
329     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
330     y = (y1 - 16) * FIX(255.0/219.0);
331     *r = CLAMP((y + r_add) >> SCALEBITS);
332     *g = CLAMP((y + g_add) >> SCALEBITS);
333     *b = CLAMP((y + b_add) >> SCALEBITS);
334 }
335
336 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
337                                int r, int g, int b )
338 {
339     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
340     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
341     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
342 }
343
344 /***********************************************************************
345  * YUVA
346  ***********************************************************************/
347 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
348                        picture_t *p_dst_orig, picture_t *p_src,
349                        int i_x_offset, int i_y_offset,
350                        int i_width, int i_height, int i_alpha )
351 {
352     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
353     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
354     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
355     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
356     uint8_t *p_trans;
357     int i_x, i_y, i_trans = 0;
358     vlc_bool_t b_even_scanline = i_y_offset % 2;
359
360     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
361     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
362               p_filter->fmt_out.video.i_x_offset +
363               p_dst->p[Y_PLANE].i_pitch *
364               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
365     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
366               p_filter->fmt_out.video.i_x_offset/2 +
367               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
368               p_dst->p[U_PLANE].i_pitch;
369     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
370               p_filter->fmt_out.video.i_x_offset/2 +
371               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
372               p_dst->p[V_PLANE].i_pitch;
373
374     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
375     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
376                p_filter->fmt_out.video.i_x_offset +
377                p_dst_orig->p[Y_PLANE].i_pitch *
378                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
379     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
380                p_filter->fmt_out.video.i_x_offset/2 +
381                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
382                p_dst_orig->p[U_PLANE].i_pitch;
383     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
384                p_filter->fmt_out.video.i_x_offset/2 +
385                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
386                p_dst_orig->p[V_PLANE].i_pitch;
387
388     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
389     p_src2_y = p_src->p[Y_PLANE].p_pixels +
390                p_filter->fmt_in.video.i_x_offset +
391                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
392     p_src2_u = p_src->p[U_PLANE].p_pixels +
393                p_filter->fmt_in.video.i_x_offset/2 +
394                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
395     p_src2_v = p_src->p[V_PLANE].p_pixels +
396                p_filter->fmt_in.video.i_x_offset/2 +
397                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
398
399     p_trans = p_src->p[A_PLANE].p_pixels +
400               p_filter->fmt_in.video.i_x_offset +
401               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
402
403 #define MAX_TRANS 255
404 #define TRANS_BITS  8
405
406     /* Draw until we reach the bottom of the subtitle */
407     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
408          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
409          p_src2_y += i_src2_pitch,
410          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
411          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
412          p_src2_u += i_src2_pitch,
413          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
414          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
415          p_src2_v += i_src2_pitch )
416     {
417         b_even_scanline = !b_even_scanline;
418
419         /* Draw until we reach the end of the line */
420         for( i_x = 0; i_x < i_width; i_x++ )
421         {
422             if( p_trans )
423                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
424             if( !i_trans )
425             {
426                 /* Completely transparent. Don't change pixel */
427                 continue;
428             }
429             else if( i_trans == MAX_TRANS )
430             {
431                 /* Completely opaque. Completely overwrite underlying pixel */
432                 p_dst_y[i_x] = p_src2_y[i_x];
433
434                 if( b_even_scanline && i_x % 2 == 0 )
435                 {
436                     p_dst_u[i_x/2] = p_src2_u[i_x];
437                     p_dst_v[i_x/2] = p_src2_v[i_x];
438                 }
439                 continue;
440             }
441
442             /* Blending */
443             p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
444                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
445                 >> TRANS_BITS;
446
447             if( b_even_scanline && i_x % 2 == 0 )
448             {
449                 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
450                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
451                 >> TRANS_BITS;
452                 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
453                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
454                 >> TRANS_BITS;
455             }
456         }
457     }
458
459 #undef MAX_TRANS
460 #undef TRANS_BITS
461
462     return;
463 }
464
465 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
466                       picture_t *p_dst_orig, picture_t *p_src,
467                       int i_x_offset, int i_y_offset,
468                       int i_width, int i_height, int i_alpha )
469 {
470     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
471     uint8_t *p_dst, *p_src1, *p_src2_y;
472     uint8_t *p_src2_u, *p_src2_v;
473     uint8_t *p_trans;
474     int i_x, i_y, i_pix_pitch, i_trans = 0;
475     int r, g, b;
476
477     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
478     i_dst_pitch = p_dst_pic->p->i_pitch;
479     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
480             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
481             p_dst_pic->p->i_pitch *
482             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
483
484     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
485     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
486                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
487                p_dst_orig->p->i_pitch *
488                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
489
490     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
491     p_src2_y = p_src->p[Y_PLANE].p_pixels +
492                p_filter->fmt_in.video.i_x_offset +
493                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
494     p_src2_u = p_src->p[U_PLANE].p_pixels +
495                p_filter->fmt_in.video.i_x_offset/2 +
496                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
497     p_src2_v = p_src->p[V_PLANE].p_pixels +
498                p_filter->fmt_in.video.i_x_offset/2 +
499                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
500
501     p_trans = p_src->p[A_PLANE].p_pixels +
502               p_filter->fmt_in.video.i_x_offset +
503               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
504
505 #define MAX_TRANS 255
506 #define TRANS_BITS  8
507
508     /* Draw until we reach the bottom of the subtitle */
509     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
510          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
511          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
512          p_src2_v += i_src2_pitch )
513     {
514         /* Draw until we reach the end of the line */
515         for( i_x = 0; i_x < i_width; i_x++ )
516         {
517             if( p_trans )
518                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
519             if( !i_trans )
520             {
521                 /* Completely transparent. Don't change pixel */
522                 continue;
523             }
524             else if( i_trans == MAX_TRANS )
525             {
526                 /* Completely opaque. Completely overwrite underlying pixel */
527                 yuv_to_rgb( &r, &g, &b,
528                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
529
530     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
531                 continue;
532             }
533
534             /* Blending */
535             /* FIXME: do the blending */
536             yuv_to_rgb( &r, &g, &b,
537                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
538
539     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
540         }
541     }
542
543 #undef MAX_TRANS
544 #undef TRANS_BITS
545
546     return;
547 }
548
549 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
550                       picture_t *p_dst_orig, picture_t *p_src,
551                       int i_x_offset, int i_y_offset,
552                       int i_width, int i_height, int i_alpha )
553 {
554     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
555     uint8_t *p_dst, *p_src1, *p_src2_y;
556     uint8_t *p_src2_u, *p_src2_v;
557     uint8_t *p_trans;
558     int i_x, i_y, i_pix_pitch, i_trans = 0;
559     int r, g, b;
560
561     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
562     i_dst_pitch = p_dst_pic->p->i_pitch;
563     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
564             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
565             p_dst_pic->p->i_pitch *
566             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
567
568     i_src1_pitch = p_dst_orig->p->i_pitch;
569     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
570                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
571                p_dst_orig->p->i_pitch *
572                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
573
574     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
575     p_src2_y = p_src->p[Y_PLANE].p_pixels +
576                p_filter->fmt_in.video.i_x_offset +
577                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
578     p_src2_u = p_src->p[U_PLANE].p_pixels +
579                p_filter->fmt_in.video.i_x_offset/2 +
580                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
581     p_src2_v = p_src->p[V_PLANE].p_pixels +
582                p_filter->fmt_in.video.i_x_offset/2 +
583                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
584
585     p_trans = p_src->p[A_PLANE].p_pixels +
586               p_filter->fmt_in.video.i_x_offset +
587               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
588
589 #define MAX_TRANS 255
590 #define TRANS_BITS  8
591
592     if( (i_pix_pitch == 4)
593      && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
594           & 3) == 0) )
595     {
596         /*
597         ** if picture pixels are 32 bits long and lines addresses are 32 bit
598         ** aligned, 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 }