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