Untested RGBA -> RV16 blending (I420 and RV24 work fine).
[vlc.git] / 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 /* YUVP */
61 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
62                           int, int, int, int, int );
63 static void BlendPalYUVPacked( filter_t *, picture_t *, picture_t *, picture_t *,
64                                int, int, int, int, int );
65 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
66                         int, int, int, int, int );
67
68 /* RGBA */
69 static void BlendRGBAI420( filter_t *, picture_t *, picture_t *, picture_t *,
70                            int, int, int, int, int );
71 static void BlendRGBAR16( filter_t *, picture_t *, picture_t *, picture_t *,
72                           int, int, int, int, int );
73 static void BlendRGBAR24( filter_t *, picture_t *, picture_t *, picture_t *,
74                           int, int, int, int, int );
75
76 /*****************************************************************************
77  * Module descriptor
78  *****************************************************************************/
79 vlc_module_begin();
80     set_description( _("Video pictures blending") );
81     set_capability( "video blending", 100 );
82     set_callbacks( OpenFilter, CloseFilter );
83 vlc_module_end();
84
85 /*****************************************************************************
86  * OpenFilter: probe the filter and return score
87  *****************************************************************************/
88 static int OpenFilter( vlc_object_t *p_this )
89 {
90     filter_t *p_filter = (filter_t*)p_this;
91     filter_sys_t *p_sys;
92
93     /* Check if we can handle that format.
94      * We could try to use a chroma filter if we can't. */
95     int in_chroma = p_filter->fmt_in.video.i_chroma;
96     int out_chroma = p_filter->fmt_out.video.i_chroma;
97     if(
98       ( ( in_chroma  != VLC_FOURCC('Y','U','V','A') &&
99           in_chroma  != VLC_FOURCC('Y','U','V','P') ) ||
100         ( out_chroma != VLC_FOURCC('I','4','2','0') &&
101           out_chroma != VLC_FOURCC('Y','U','Y','2') &&
102           out_chroma != VLC_FOURCC('Y','V','1','2') &&
103           out_chroma != VLC_FOURCC('U','Y','V','Y') &&
104           out_chroma != VLC_FOURCC('Y','V','Y','U') &&
105           out_chroma != VLC_FOURCC('R','V','1','6') &&
106           out_chroma != VLC_FOURCC('R','V','2','4') &&
107           out_chroma != VLC_FOURCC('R','V','3','2') ) )
108       &&
109       ( ( in_chroma  != VLC_FOURCC('R','G','B','A') ) ||
110         ( out_chroma != VLC_FOURCC('I','4','2','0') &&
111           out_chroma != VLC_FOURCC('Y','V','1','2') &&
112           out_chroma != VLC_FOURCC('R','V','1','6') &&
113           out_chroma != VLC_FOURCC('R','V','2','4') &&
114           out_chroma != VLC_FOURCC('R','V','3','2' ) ) )
115       )
116     {
117         return VLC_EGENERIC;
118     }
119
120     /* Allocate the memory needed to store the decoder's structure */
121     if( ( p_filter->p_sys = p_sys =
122           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
123     {
124         msg_Err( p_filter, "out of memory" );
125         return VLC_EGENERIC;
126     }
127
128     /* Misc init */
129     p_filter->pf_video_blend = Blend;
130
131     msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
132              (char *)&p_filter->fmt_in.video.i_chroma,
133              (char *)&p_filter->fmt_out.video.i_chroma );
134
135
136     return VLC_SUCCESS;
137 }
138
139 /*****************************************************************************
140  * CloseFilter: clean up the filter
141  *****************************************************************************/
142 static void CloseFilter( vlc_object_t *p_this )
143 {
144     filter_t *p_filter = (filter_t*)p_this;
145     filter_sys_t *p_sys = p_filter->p_sys;
146
147     free( p_sys );
148 }
149
150 /****************************************************************************
151  * Blend: the whole thing
152  ****************************************************************************
153  * This function is called just after the thread is launched.
154  ****************************************************************************/
155 static void Blend( filter_t *p_filter, picture_t *p_dst,
156                    picture_t *p_dst_orig, picture_t *p_src,
157                    int i_x_offset, int i_y_offset, int i_alpha )
158 {
159     int i_width, i_height;
160
161     i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
162                     (int)p_filter->fmt_in.video.i_visible_width);
163
164     i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
165                      (int)p_filter->fmt_in.video.i_visible_height);
166
167     if( i_width <= 0 || i_height <= 0 ) return;
168
169 #if 0
170     printf( "chroma: %4.4s -> %4.4s\n",
171              (char *)&p_filter->fmt_in.video.i_chroma,
172              (char *)&p_filter->fmt_out.video.i_chroma );
173 #endif
174
175     switch( p_filter->fmt_in.video.i_chroma )
176     {
177         case VLC_FOURCC('Y','U','V','A'):
178             switch( p_filter->fmt_out.video.i_chroma )
179             {
180                 case VLC_FOURCC('I','4','2','0'):
181                 case VLC_FOURCC('Y','V','1','2'):
182                     BlendI420( p_filter, p_dst, p_dst_orig, p_src,
183                                i_x_offset, i_y_offset,
184                                i_width, i_height, i_alpha );
185                     return;
186                 case VLC_FOURCC('Y','U','Y','2'):
187                 case VLC_FOURCC('U','Y','V','Y'):
188                 case VLC_FOURCC('Y','V','Y','U'):
189                     BlendYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
190                                     i_x_offset, i_y_offset,
191                                     i_width, i_height, i_alpha );
192                     return;
193                 case VLC_FOURCC('R','V','1','6'):
194                     BlendR16( p_filter, p_dst, p_dst_orig, p_src,
195                               i_x_offset, i_y_offset,
196                               i_width, i_height, i_alpha );
197                     return;
198                 case VLC_FOURCC('R','V','2','4'):
199                 case VLC_FOURCC('R','V','3','2'):
200                     BlendR24( 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             }
205         case VLC_FOURCC('Y','U','V','P'):
206             switch( p_filter->fmt_out.video.i_chroma )
207             {
208                 case VLC_FOURCC('I','4','2','0'):
209                 case VLC_FOURCC('Y','V','1','2'):
210                     BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
211                                   i_x_offset, i_y_offset,
212                                   i_width, i_height, i_alpha );
213                     return;
214                 case VLC_FOURCC('Y','U','Y','2'):
215                 case VLC_FOURCC('U','Y','V','Y'):
216                 case VLC_FOURCC('Y','V','Y','U'):
217                     BlendPalYUVPacked( p_filter, p_dst, p_dst_orig, p_src,
218                                        i_x_offset, i_y_offset,
219                                        i_width, i_height, i_alpha );
220                     return;
221                 case VLC_FOURCC('R','V','1','6'):
222                 case VLC_FOURCC('R','V','2','4'):
223                 case VLC_FOURCC('R','V','3','2'):
224                     BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
225                                 i_x_offset, i_y_offset,
226                                 i_width, i_height, i_alpha );
227                     return;
228             }
229         case VLC_FOURCC('R','G','B','A'):
230             switch( p_filter->fmt_out.video.i_chroma )
231             {
232                 case VLC_FOURCC('I','4','2','0'):
233                 case VLC_FOURCC('Y','V','1','2'):
234                     BlendRGBAI420( p_filter, p_dst, p_dst_orig, p_src,
235                                    i_x_offset, i_y_offset,
236                                    i_width, i_height, i_alpha );
237                     return;
238                 case VLC_FOURCC('R','V','2','4'):
239                 case VLC_FOURCC('R','V','3','2'):
240                     BlendRGBAR24( p_filter, p_dst, p_dst_orig, p_src,
241                                   i_x_offset, i_y_offset,
242                                   i_width, i_height, i_alpha );
243                     return;
244                 case VLC_FOURCC('R','V','1','6'):
245                     BlendRGBAR16( p_filter, p_dst, p_dst_orig, p_src,
246                                   i_x_offset, i_y_offset,
247                                   i_width, i_height, i_alpha );
248                     return;
249             }
250     }
251
252     msg_Dbg( p_filter, "no matching alpha blending routine "
253              "(chroma: %4.4s -> %4.4s)",
254              (char *)&p_filter->fmt_in.video.i_chroma,
255              (char *)&p_filter->fmt_out.video.i_chroma );
256 }
257
258 /***********************************************************************
259  * Utils
260  ***********************************************************************/
261 static inline void yuv_to_rgb( int *r, int *g, int *b,
262                                uint8_t y1, uint8_t u1, uint8_t v1 )
263 {
264     /* macros used for YUV pixel conversions */
265 #   define SCALEBITS 10
266 #   define ONE_HALF  (1 << (SCALEBITS - 1))
267 #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
268 #   define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
269
270     int y, cb, cr, r_add, g_add, b_add;
271
272     cb = u1 - 128;
273     cr = v1 - 128;
274     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
275     g_add = - FIX(0.34414*255.0/224.0) * cb
276             - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
277     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
278     y = (y1 - 16) * FIX(255.0/219.0);
279     *r = CLAMP((y + r_add) >> SCALEBITS);
280     *g = CLAMP((y + g_add) >> SCALEBITS);
281     *b = CLAMP((y + b_add) >> SCALEBITS);
282 }
283
284 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
285                                int r, int g, int b )
286 {
287     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
288     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
289     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
290 }
291
292 /***********************************************************************
293  * YUVA
294  ***********************************************************************/
295 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
296                        picture_t *p_dst_orig, picture_t *p_src,
297                        int i_x_offset, int i_y_offset,
298                        int i_width, int i_height, int i_alpha )
299 {
300     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
301     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
302     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
303     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
304     uint8_t *p_trans;
305     int i_x, i_y, i_trans;
306     vlc_bool_t b_even_scanline = i_y_offset % 2;
307
308     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
309     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
310               p_filter->fmt_out.video.i_x_offset +
311               p_dst->p[Y_PLANE].i_pitch *
312               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
313     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
314               p_filter->fmt_out.video.i_x_offset/2 +
315               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
316               p_dst->p[U_PLANE].i_pitch;
317     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
318               p_filter->fmt_out.video.i_x_offset/2 +
319               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
320               p_dst->p[V_PLANE].i_pitch;
321
322     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
323     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
324                p_filter->fmt_out.video.i_x_offset +
325                p_dst_orig->p[Y_PLANE].i_pitch *
326                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
327     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
328                p_filter->fmt_out.video.i_x_offset/2 +
329                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
330                p_dst_orig->p[U_PLANE].i_pitch;
331     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
332                p_filter->fmt_out.video.i_x_offset/2 +
333                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
334                p_dst_orig->p[V_PLANE].i_pitch;
335
336     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
337     p_src2_y = p_src->p[Y_PLANE].p_pixels +
338                p_filter->fmt_in.video.i_x_offset +
339                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
340     p_src2_u = p_src->p[U_PLANE].p_pixels +
341                p_filter->fmt_in.video.i_x_offset/2 +
342                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
343     p_src2_v = p_src->p[V_PLANE].p_pixels +
344                p_filter->fmt_in.video.i_x_offset/2 +
345                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
346
347     p_trans = p_src->p[A_PLANE].p_pixels +
348               p_filter->fmt_in.video.i_x_offset +
349               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
350
351 #define MAX_TRANS 255
352 #define TRANS_BITS  8
353
354     /* Draw until we reach the bottom of the subtitle */
355     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
356          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
357          p_src2_y += i_src2_pitch,
358          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
359          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
360          p_src2_u += i_src2_pitch,
361          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
362          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
363          p_src2_v += i_src2_pitch )
364     {
365         b_even_scanline = !b_even_scanline;
366
367         /* Draw until we reach the end of the line */
368         for( i_x = 0; i_x < i_width; i_x++ )
369         {
370             i_trans = ( p_trans[i_x] * i_alpha ) / 255;
371             if( !i_trans )
372             {
373                 /* Completely transparent. Don't change pixel */
374                 continue;
375             }
376             else if( i_trans == MAX_TRANS )
377             {
378                 /* Completely opaque. Completely overwrite underlying pixel */
379                 p_dst_y[i_x] = p_src2_y[i_x];
380
381                 if( b_even_scanline && i_x % 2 == 0 )
382                 {
383                     p_dst_u[i_x/2] = p_src2_u[i_x];
384                     p_dst_v[i_x/2] = p_src2_v[i_x];
385                 }
386                 continue;
387             }
388
389             /* Blending */
390             p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
391                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
392                 >> TRANS_BITS;
393
394             if( b_even_scanline && i_x % 2 == 0 )
395             {
396                 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
397                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
398                 >> TRANS_BITS;
399                 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
400                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
401                 >> TRANS_BITS;
402             }
403         }
404     }
405
406 #undef MAX_TRANS
407 #undef TRANS_BITS
408
409     return;
410 }
411
412 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
413                       picture_t *p_dst_orig, picture_t *p_src,
414                       int i_x_offset, int i_y_offset,
415                       int i_width, int i_height, int i_alpha )
416 {
417     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
418     uint8_t *p_dst, *p_src1, *p_src2_y;
419     uint8_t *p_src2_u, *p_src2_v;
420     uint8_t *p_trans;
421     int i_x, i_y, i_pix_pitch;
422     int r, g, b;
423
424     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
425     i_dst_pitch = p_dst_pic->p->i_pitch;
426     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
427             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
428             p_dst_pic->p->i_pitch *
429             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
430
431     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
432     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
433                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
434                p_dst_orig->p->i_pitch *
435                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
436
437     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
438     p_src2_y = p_src->p[Y_PLANE].p_pixels +
439                p_filter->fmt_in.video.i_x_offset +
440                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
441     p_src2_u = p_src->p[U_PLANE].p_pixels +
442                p_filter->fmt_in.video.i_x_offset/2 +
443                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
444     p_src2_v = p_src->p[V_PLANE].p_pixels +
445                p_filter->fmt_in.video.i_x_offset/2 +
446                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
447
448     p_trans = p_src->p[A_PLANE].p_pixels +
449               p_filter->fmt_in.video.i_x_offset +
450               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
451
452 #define MAX_TRANS 255
453 #define TRANS_BITS  8
454
455     /* Draw until we reach the bottom of the subtitle */
456     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
457          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
458          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
459          p_src2_v += i_src2_pitch )
460     {
461         /* Draw until we reach the end of the line */
462         for( i_x = 0; i_x < i_width; i_x++ )
463         {
464             if( !p_trans[i_x] )
465             {
466                 /* Completely transparent. Don't change pixel */
467                 continue;
468             }
469             else if( p_trans[i_x] == MAX_TRANS )
470             {
471                 /* Completely opaque. Completely overwrite underlying pixel */
472                 yuv_to_rgb( &r, &g, &b,
473                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
474
475     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
476                 continue;
477             }
478
479             /* Blending */
480             yuv_to_rgb( &r, &g, &b,
481                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
482
483     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
484         }
485     }
486
487 #undef MAX_TRANS
488 #undef TRANS_BITS
489
490     return;
491 }
492
493 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
494                       picture_t *p_dst_orig, picture_t *p_src,
495                       int i_x_offset, int i_y_offset,
496                       int i_width, int i_height, int i_alpha )
497 {
498     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
499     uint8_t *p_dst, *p_src1, *p_src2_y;
500     uint8_t *p_src2_u, *p_src2_v;
501     uint8_t *p_trans;
502     int i_x, i_y, i_pix_pitch, i_trans;
503     int r, g, b;
504
505     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
506     i_dst_pitch = p_dst_pic->p->i_pitch;
507     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
508             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
509             p_dst_pic->p->i_pitch *
510             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
511
512     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
513     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
514                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
515                p_dst_orig->p->i_pitch *
516                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
517
518     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
519     p_src2_y = p_src->p[Y_PLANE].p_pixels +
520                p_filter->fmt_in.video.i_x_offset +
521                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
522     p_src2_u = p_src->p[U_PLANE].p_pixels +
523                p_filter->fmt_in.video.i_x_offset/2 +
524                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
525     p_src2_v = p_src->p[V_PLANE].p_pixels +
526                p_filter->fmt_in.video.i_x_offset/2 +
527                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
528
529     p_trans = p_src->p[A_PLANE].p_pixels +
530               p_filter->fmt_in.video.i_x_offset +
531               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
532
533 #define MAX_TRANS 255
534 #define TRANS_BITS  8
535
536     /* Draw until we reach the bottom of the subtitle */
537     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
538          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
539          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
540          p_src2_v += i_src2_pitch )
541     {
542         /* Draw until we reach the end of the line */
543         for( i_x = 0; i_x < i_width; i_x++ )
544         {
545             i_trans = ( p_trans[i_x] * i_alpha ) / 255;
546             if( !i_trans )
547             {
548                 /* Completely transparent. Don't change pixel */
549                 continue;
550             }
551             else if( i_trans == MAX_TRANS )
552             {
553                 /* Completely opaque. Completely overwrite underlying pixel */
554                 yuv_to_rgb( &r, &g, &b,
555                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
556
557                 p_dst[i_x * i_pix_pitch]     = r;
558                 p_dst[i_x * i_pix_pitch + 1] = g;
559                 p_dst[i_x * i_pix_pitch + 2] = b;
560                 continue;
561             }
562
563             /* Blending */
564             yuv_to_rgb( &r, &g, &b,
565                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
566
567             p_dst[i_x * i_pix_pitch]     = ( r * i_trans +
568                 (uint16_t)p_src1[i_x * i_pix_pitch] *
569                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
570             p_dst[i_x * i_pix_pitch + 1] = ( g * i_trans +
571                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
572                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
573             p_dst[i_x * i_pix_pitch + 2] = ( b * i_trans +
574                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
575                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
576         }
577     }
578
579 #undef MAX_TRANS
580 #undef TRANS_BITS
581
582     return;
583 }
584
585 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
586                             picture_t *p_dst_orig, picture_t *p_src,
587                             int i_x_offset, int i_y_offset,
588                             int i_width, int i_height, int i_alpha )
589 {
590     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
591     uint8_t *p_dst, *p_src1, *p_src2_y;
592     uint8_t *p_src2_u, *p_src2_v;
593     uint8_t *p_trans;
594     int i_x, i_y, i_pix_pitch, i_trans;
595     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
596     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
597
598     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
599     {
600         i_l_offset = 0;
601         i_u_offset = 1;
602         i_v_offset = 3;
603     }
604     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
605     {
606         i_l_offset = 1;
607         i_u_offset = 0;
608         i_v_offset = 2;
609     }
610     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
611     {
612         i_l_offset = 0;
613         i_u_offset = 3;
614         i_v_offset = 1;
615     }
616
617     i_pix_pitch = 2;
618     i_dst_pitch = p_dst_pic->p->i_pitch;
619     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
620             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
621             p_dst_pic->p->i_pitch *
622             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
623
624     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
625     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
626                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
627                p_dst_orig->p->i_pitch *
628                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
629
630     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
631     p_src2_y = p_src->p[Y_PLANE].p_pixels +
632                p_filter->fmt_in.video.i_x_offset +
633                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
634     p_src2_u = p_src->p[U_PLANE].p_pixels +
635                p_filter->fmt_in.video.i_x_offset/2 +
636                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
637     p_src2_v = p_src->p[V_PLANE].p_pixels +
638                p_filter->fmt_in.video.i_x_offset/2 +
639                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
640
641     p_trans = p_src->p[A_PLANE].p_pixels +
642               p_filter->fmt_in.video.i_x_offset +
643               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
644
645     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
646
647 #define MAX_TRANS 255
648 #define TRANS_BITS  8
649
650     /* Draw until we reach the bottom of the subtitle */
651     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
652          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
653          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
654          p_src2_v += i_src2_pitch )
655     {
656         /* Draw until we reach the end of the line */
657         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
658         {
659             i_trans = ( p_trans[i_x] * i_alpha ) / 255;
660             if( !i_trans )
661             {
662                 /* Completely transparent. Don't change pixel */
663             }
664             else if( i_trans == MAX_TRANS )
665             {
666                 /* Completely opaque. Completely overwrite underlying pixel */
667                 p_dst[i_x * 2 + i_l_offset]     = p_src2_y[i_x];
668
669                 if( b_even )
670                 {
671                     if( p_trans[i_x+1] > 0xaa )
672                     {
673                         p_dst[i_x * 2 + i_u_offset] = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
674                         p_dst[i_x * 2 + i_v_offset] = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
675                     }
676                     else
677                     {
678                         p_dst[i_x * 2 + i_u_offset] = p_src2_u[i_x];
679                         p_dst[i_x * 2 + i_v_offset] = p_src2_v[i_x];
680                     }
681                 }
682             }
683             else
684             {
685                 /* Blending */
686                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)p_src2_y[i_x] * i_trans +
687                     (uint16_t)p_src1[i_x * 2 + i_l_offset] * (MAX_TRANS - i_trans) )
688                     >> TRANS_BITS;
689
690                 if( b_even )
691                 {
692                     uint16_t i_u = 0;
693                     uint16_t i_v = 0;
694                     if( p_trans[i_x+1] > 0xaa )
695                     {
696                         i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
697                         i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
698                     }
699                     else
700                     {
701                         i_u = p_src2_u[i_x];
702                         i_v = p_src2_v[i_x];
703                     }
704                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u * i_trans +
705                         (uint16_t)p_src1[i_x * 2 + i_u_offset] * (MAX_TRANS - i_trans) )
706                         >> TRANS_BITS;
707                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v * i_trans +
708                         (uint16_t)p_src1[i_x * 2 + i_v_offset] * (MAX_TRANS - i_trans) )
709                         >> TRANS_BITS;
710                 }
711             }
712         }
713     }
714
715 #undef MAX_TRANS
716 #undef TRANS_BITS
717
718     return;
719 }
720
721 /***********************************************************************
722  * YUVP
723  ***********************************************************************/
724 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
725                           picture_t *p_dst_orig, picture_t *p_src,
726                           int i_x_offset, int i_y_offset,
727                           int i_width, int i_height, int i_alpha )
728 {
729     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
730     uint8_t *p_src1_y, *p_src2, *p_dst_y;
731     uint8_t *p_src1_u, *p_dst_u;
732     uint8_t *p_src1_v, *p_dst_v;
733     int i_x, i_y, i_trans;
734     vlc_bool_t b_even_scanline = i_y_offset % 2;
735
736     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
737     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
738               p_filter->fmt_out.video.i_x_offset +
739               p_dst->p[Y_PLANE].i_pitch *
740               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
741     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
742               p_filter->fmt_out.video.i_x_offset/2 +
743               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
744               p_dst->p[U_PLANE].i_pitch;
745     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
746               p_filter->fmt_out.video.i_x_offset/2 +
747               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
748               p_dst->p[V_PLANE].i_pitch;
749
750     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
751     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
752                p_filter->fmt_out.video.i_x_offset +
753                p_dst_orig->p[Y_PLANE].i_pitch *
754                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
755     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
756                p_filter->fmt_out.video.i_x_offset/2 +
757                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
758                p_dst_orig->p[U_PLANE].i_pitch;
759     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
760                p_filter->fmt_out.video.i_x_offset/2 +
761                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
762                p_dst_orig->p[V_PLANE].i_pitch;
763
764     i_src2_pitch = p_src->p->i_pitch;
765     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
766              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
767
768 #define MAX_TRANS 255
769 #define TRANS_BITS  8
770 #define p_trans p_src2
771 #define p_pal p_filter->fmt_in.video.p_palette->palette
772
773     /* Draw until we reach the bottom of the subtitle */
774     for( i_y = 0; i_y < i_height; i_y++,
775          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
776          p_src2 += i_src2_pitch,
777          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
778          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
779          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
780          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
781     {
782         b_even_scanline = !b_even_scanline;
783
784         /* Draw until we reach the end of the line */
785         for( i_x = 0; i_x < i_width; i_x++ )
786         {
787             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
788             if( !i_trans )
789             {
790                 /* Completely transparent. Don't change pixel */
791                 continue;
792             }
793             else if( i_trans == MAX_TRANS )
794             {
795                 /* Completely opaque. Completely overwrite underlying pixel */
796                 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
797
798                 if( b_even_scanline && i_x % 2 == 0 )
799                 {
800                     p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
801                     p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
802                 }
803                 continue;
804             }
805
806             /* Blending */
807             p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
808                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
809                 >> TRANS_BITS;
810
811             if( b_even_scanline && i_x % 2 == 0 )
812             {
813                 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
814                     (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
815                     >> TRANS_BITS;
816                 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
817                     (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
818                     >> TRANS_BITS;
819             }
820         }
821     }
822
823 #undef MAX_TRANS
824 #undef TRANS_BITS
825 #undef p_trans
826 #undef p_pal
827
828     return;
829 }
830
831 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
832                                picture_t *p_dst_orig, picture_t *p_src,
833                                int i_x_offset, int i_y_offset,
834                                int i_width, int i_height, int i_alpha )
835 {
836     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
837     uint8_t *p_src1, *p_src2, *p_dst;
838     int i_x, i_y, i_pix_pitch, i_trans;
839     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
840     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
841
842     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
843     {
844         i_l_offset = 0;
845         i_u_offset = 1;
846         i_v_offset = 3;
847     }
848     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
849     {
850         i_l_offset = 1;
851         i_u_offset = 0;
852         i_v_offset = 2;
853     }
854     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
855     {
856         i_l_offset = 0;
857         i_u_offset = 3;
858         i_v_offset = 1;
859     }
860
861     i_pix_pitch = 2;
862     i_dst_pitch = p_dst_pic->p->i_pitch;
863     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
864             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
865             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
866
867     i_src1_pitch = p_dst_orig->p->i_pitch;
868     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
869              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
870              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
871
872     i_src2_pitch = p_src->p->i_pitch;
873     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
874              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
875
876     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
877
878 #define MAX_TRANS 255
879 #define TRANS_BITS  8
880 #define p_trans p_src2
881 #define p_pal p_filter->fmt_in.video.p_palette->palette
882
883     /* Draw until we reach the bottom of the subtitle */
884     for( i_y = 0; i_y < i_height; i_y++,
885          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
886     {
887         /* Draw until we reach the end of the line */
888         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
889         {
890             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
891             if( !i_trans )
892             {
893                 /* Completely transparent. Don't change pixel */
894             }
895             else if( i_trans == MAX_TRANS )
896             {
897                 /* Completely opaque. Completely overwrite underlying pixel */
898                 p_dst[i_x * 2 + i_l_offset]     = p_pal[p_src2[i_x]][0];
899
900                 if( b_even )
901                 {
902                     if( p_trans[i_x+1] > 0xaa )
903                     {
904                         p_dst[i_x * 2 + i_u_offset] = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
905                         p_dst[i_x * 2 + i_v_offset] = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
906                     }
907                     else
908                     {
909                         p_dst[i_x * 2 + i_u_offset] = p_pal[p_src2[i_x]][1];
910                         p_dst[i_x * 2 + i_v_offset] = p_pal[p_src2[i_x]][2];
911                     }
912                 }
913             }
914             else
915             {
916                 /* Blending */
917                 p_dst[i_x * 2 + i_l_offset]     = ( (uint16_t)p_pal[p_src2[i_x]][0] *
918                     i_trans + (uint16_t)p_src1[i_x * 2 + i_l_offset] *
919                     (MAX_TRANS - i_trans) ) >> TRANS_BITS;
920
921                 if( b_even )
922                 {
923                     uint16_t i_u = 0;
924                     uint16_t i_v = 0;
925                     if( p_trans[i_x+1] > 0xaa )
926                     {
927                         i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
928                         i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
929                     }
930                     else
931                     {
932                         i_u = p_pal[p_src2[i_x]][1];
933                         i_v = p_pal[p_src2[i_x]][2];
934                     }
935
936                     p_dst[i_x * 2 + i_u_offset] = ( (uint16_t)i_u *
937                         i_trans + (uint16_t)p_src1[i_x * 2 + i_u_offset] *
938                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
939                     p_dst[i_x * 2 + i_v_offset] = ( (uint16_t)i_v *
940                         i_trans + (uint16_t)p_src1[i_x * 2 + i_v_offset] *
941                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
942                 }
943             }
944         }
945     }
946
947 #undef MAX_TRANS
948 #undef TRANS_BITS
949 #undef p_trans
950 #undef p_pal
951
952     return;
953 }
954
955 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
956                         picture_t *p_dst_orig, picture_t *p_src,
957                         int i_x_offset, int i_y_offset,
958                         int i_width, int i_height, int i_alpha )
959 {
960     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
961     uint8_t *p_src1, *p_src2, *p_dst;
962     int i_x, i_y, i_pix_pitch, i_trans;
963     int r, g, b;
964     video_palette_t rgbpalette;
965
966     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
967     i_dst_pitch = p_dst_pic->p->i_pitch;
968     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
969             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
970             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
971
972     i_src1_pitch = p_dst_orig->p->i_pitch;
973     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
974              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
975              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
976
977     i_src2_pitch = p_src->p->i_pitch;
978     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
979              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
980
981 #define MAX_TRANS 255
982 #define TRANS_BITS  8
983 #define p_trans p_src2
984 #define p_pal p_filter->fmt_in.video.p_palette->palette
985 #define rgbpal rgbpalette.palette
986
987     /* Convert palette first */
988     for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
989          i_y < 256; i_y++ )
990     {
991         yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
992
993         if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
994         {
995             *(uint16_t *)rgbpal[i_y] =
996                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
997         }
998         else
999         {
1000             rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1001         }
1002     }
1003
1004     /* Draw until we reach the bottom of the subtitle */
1005     for( i_y = 0; i_y < i_height; i_y++,
1006          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1007     {
1008         /* Draw until we reach the end of the line */
1009         for( i_x = 0; i_x < i_width; i_x++ )
1010         {
1011             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1012             if( !i_trans )
1013             {
1014                 /* Completely transparent. Don't change pixel */
1015                 continue;
1016             }
1017             else if( i_trans == MAX_TRANS ||
1018                      p_filter->fmt_out.video.i_chroma ==
1019                      VLC_FOURCC('R','V','1','6') )
1020             {
1021                 /* Completely opaque. Completely overwrite underlying pixel */
1022                 p_dst[i_x * i_pix_pitch]     = rgbpal[p_src2[i_x]][0];
1023                 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1024                 if( p_filter->fmt_out.video.i_chroma !=
1025                     VLC_FOURCC('R','V','1','6') )
1026                 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1027                 continue;
1028             }
1029
1030             /* Blending */
1031             p_dst[i_x * i_pix_pitch]     = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
1032                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
1033                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1034             p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
1035                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1036                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1037             p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
1038                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1039                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1040         }
1041     }
1042
1043 #undef MAX_TRANS
1044 #undef TRANS_BITS
1045 #undef p_trans
1046 #undef p_pal
1047 #undef rgbpal
1048
1049     return;
1050 }
1051
1052 /***********************************************************************
1053  * RGBA
1054  ***********************************************************************/
1055 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1056                            picture_t *p_dst_orig, picture_t *p_src,
1057                            int i_x_offset, int i_y_offset,
1058                            int i_width, int i_height, int i_alpha )
1059 {
1060     int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1061     uint8_t *p_src1_y, *p_dst_y;
1062     uint8_t *p_src1_u, *p_dst_u;
1063     uint8_t *p_src1_v, *p_dst_v;
1064     uint8_t *p_src2;
1065     int i_x, i_y, i_trans;
1066     uint8_t y, u, v;
1067
1068     vlc_bool_t b_even_scanline = i_y_offset % 2;
1069
1070     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1071     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1072               p_filter->fmt_out.video.i_x_offset +
1073               p_dst->p[Y_PLANE].i_pitch *
1074               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1075     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1076               p_filter->fmt_out.video.i_x_offset/2 +
1077               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1078               p_dst->p[U_PLANE].i_pitch;
1079     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1080               p_filter->fmt_out.video.i_x_offset/2 +
1081               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1082               p_dst->p[V_PLANE].i_pitch;
1083
1084     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1085     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1086                p_filter->fmt_out.video.i_x_offset +
1087                p_dst_orig->p[Y_PLANE].i_pitch *
1088                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1089     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1090                p_filter->fmt_out.video.i_x_offset/2 +
1091                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1092                p_dst_orig->p[U_PLANE].i_pitch;
1093     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1094                p_filter->fmt_out.video.i_x_offset/2 +
1095                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1096                p_dst_orig->p[V_PLANE].i_pitch;
1097
1098     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1099     i_src2_pitch = p_src->p->i_pitch;
1100     p_src2 = p_src->p->p_pixels +
1101              p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1102              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1103
1104
1105 #define MAX_TRANS 255
1106 #define TRANS_BITS  8
1107
1108     /* Draw until we reach the bottom of the subtitle */
1109     for( i_y = 0; i_y < i_height; i_y++,
1110          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1111          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1112          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1113          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1114          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1115          p_src2 += i_src2_pitch )
1116     {
1117         b_even_scanline = !b_even_scanline;
1118
1119         /* Draw until we reach the end of the line */
1120         for( i_x = 0; i_x < i_width; i_x++ )
1121         {
1122 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1123 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1124 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1125             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1126             if( !i_trans )
1127             {
1128                 /* Completely transparent. Don't change pixel */
1129                 continue;
1130             }
1131             else if( i_trans == MAX_TRANS )
1132             {
1133                 /* Completely opaque. Completely overwrite underlying pixel */
1134                 rgb_to_yuv( &y, &u, &v, R, G, B );
1135                 p_dst_y[i_x] = y;
1136
1137                 if( b_even_scanline && i_x % 2 == 0 )
1138                 {
1139                     p_dst_u[i_x/2] = u;
1140                     p_dst_v[i_x/2] = v;
1141                 }
1142                 continue;
1143             }
1144
1145             /* Blending */
1146             rgb_to_yuv( &y, &u, &v, R, G, B );
1147             p_dst_y[i_x] = ( (uint16_t)y * i_trans +
1148                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
1149                 >> TRANS_BITS;
1150
1151             if( b_even_scanline && i_x % 2 == 0 )
1152             {
1153                 p_dst_u[i_x/2] = ( (uint16_t)u * i_trans +
1154                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
1155                 >> TRANS_BITS;
1156                 p_dst_v[i_x/2] = ( (uint16_t)v * i_trans +
1157                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
1158                 >> TRANS_BITS;
1159             }
1160 #undef      R
1161 #undef      G
1162 #undef      B
1163         }
1164     }
1165
1166 #undef MAX_TRANS
1167 #undef TRANS_BITS
1168
1169     return;
1170 }
1171
1172 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1173                           picture_t *p_dst_orig, picture_t *p_src,
1174                           int i_x_offset, int i_y_offset,
1175                           int i_width, int i_height, int i_alpha )
1176 {
1177     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1178     uint8_t *p_dst, *p_src1, *p_src2;
1179     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1180
1181     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1182     i_dst_pitch = p_dst_pic->p->i_pitch;
1183     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1184             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1185             p_dst_pic->p->i_pitch *
1186             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1187
1188     i_src1_pitch = p_dst_orig->p->i_pitch;
1189     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1190              p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1191              p_dst_orig->p->i_pitch *
1192              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1193
1194     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1195     i_src2_pitch = p_src->p->i_pitch;
1196     p_src2 = p_src->p->p_pixels +
1197              p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1198              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1199
1200 #define MAX_TRANS 255
1201 #define TRANS_BITS  8
1202
1203     /* Draw until we reach the bottom of the subtitle */
1204     for( i_y = 0; i_y < i_height; i_y++,
1205          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1206     {
1207         /* Draw until we reach the end of the line */
1208         for( i_x = 0; i_x < i_width; i_x++ )
1209         {
1210 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1211 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1212 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1213             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1214             if( !i_trans )
1215             {
1216                 /* Completely transparent. Don't change pixel */
1217                 continue;
1218             }
1219             else if( i_trans == MAX_TRANS )
1220             {
1221                 /* Completely opaque. Completely overwrite underlying pixel */
1222                 p_dst[i_x * i_pix_pitch + 0] = R;
1223                 p_dst[i_x * i_pix_pitch + 1] = G;
1224                 p_dst[i_x * i_pix_pitch + 2] = B;
1225                 continue;
1226             }
1227
1228             /* Blending */
1229             p_dst[i_x * i_pix_pitch + 0] = ( R * i_trans +
1230                 (uint16_t)p_src1[i_x * i_pix_pitch + 0] *
1231                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1232             p_dst[i_x * i_pix_pitch + 1] = ( G * i_trans +
1233                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
1234                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1235             p_dst[i_x * i_pix_pitch + 2] = ( B * i_trans +
1236                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
1237                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
1238 #undef      R
1239 #undef      G
1240 #undef      B
1241         }
1242     }
1243
1244 #undef MAX_TRANS
1245 #undef TRANS_BITS
1246
1247     return;
1248 }
1249
1250 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1251                           picture_t *p_dst_orig, picture_t *p_src,
1252                           int i_x_offset, int i_y_offset,
1253                           int i_width, int i_height, int i_alpha )
1254 {
1255     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1256     uint8_t *p_dst, *p_src1, *p_src2;
1257     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1258     uint16_t i_pix;
1259
1260     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1261     i_dst_pitch = p_dst_pic->p->i_pitch;
1262     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1263             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1264             p_dst_pic->p->i_pitch *
1265             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1266
1267     i_src1_pitch = p_dst_orig->p->i_pitch;
1268     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1269              p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1270              p_dst_orig->p->i_pitch *
1271              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1272
1273     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1274     i_src2_pitch = p_src->p->i_pitch;
1275     p_src2 = p_src->p->p_pixels +
1276              p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1277              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1278
1279 #define MAX_TRANS 255
1280 #define TRANS_BITS  8
1281
1282     /* Draw until we reach the bottom of the subtitle */
1283     for( i_y = 0; i_y < i_height; i_y++,
1284          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1285     {
1286         /* Draw until we reach the end of the line */
1287         for( i_x = 0; i_x < i_width; i_x++ )
1288         {
1289 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1290 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1291 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1292             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1293             if( !i_trans )
1294             {
1295                 /* Completely transparent. Don't change pixel */
1296                 continue;
1297             }
1298             else if( i_trans == MAX_TRANS )
1299             {
1300                 /* Completely opaque. Completely overwrite underlying pixel */
1301                 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1302                 continue;
1303             }
1304
1305             /* Blending */
1306             i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1307             *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1308                 ( ( ( (R >> 3)*i_trans
1309                     + (i_pix >> 11) * (MAX_TRANS - i_trans) )
1310                     >> TRANS_BITS ) << 11 )
1311               | ( ( ( (G >> 2)*i_trans
1312                     + ((i_pix & 0x07e0)>> 5) * (MAX_TRANS - i_trans) )
1313                     >> TRANS_BITS ) << 5  )
1314               | ( ( ( (B >> 3)*i_trans
1315                     + (i_pix & 0x001f) * (MAX_TRANS - i_trans) )
1316                     >> TRANS_BITS ) );
1317 #undef      R
1318 #undef      G
1319 #undef      B
1320         }
1321     }
1322
1323 #undef MAX_TRANS
1324 #undef TRANS_BITS
1325
1326     return;
1327 }