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