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