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