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