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