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