]> git.sesse.net Git - vlc/blob - modules/video_filter/blend.c
Begin clean up of giant blend ctl-c ctl-v.
[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 uint8_t vlc_uint8( int v )
316 {
317     if( v > 255 )
318         return 255;
319     else if( v < 0 )
320         return 0;
321     return v;
322 }
323
324 #define MAX_TRANS 255
325 #define TRANS_BITS  8
326
327 static inline int vlc_blend( int v1, int v2, int a )
328 {
329     /* TODO bench if the tests really increase speed */
330     if( a == 0 )
331         return v2;
332     else if( a == MAX_TRANS )
333         return v1;
334     return ( v1 * a + v2 * (MAX_TRANS - a ) ) >> TRANS_BITS;
335 }
336
337 static inline void yuv_to_rgb( int *r, int *g, int *b,
338                                uint8_t y1, uint8_t u1, uint8_t v1 )
339 {
340     /* macros used for YUV pixel conversions */
341 #   define SCALEBITS 10
342 #   define ONE_HALF  (1 << (SCALEBITS - 1))
343 #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
344
345     int y, cb, cr, r_add, g_add, b_add;
346
347     cb = u1 - 128;
348     cr = v1 - 128;
349     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
350     g_add = - FIX(0.34414*255.0/224.0) * cb
351             - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
352     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
353     y = (y1 - 16) * FIX(255.0/219.0);
354     *r = vlc_uint8( (y + r_add) >> SCALEBITS );
355     *g = vlc_uint8( (y + g_add) >> SCALEBITS );
356     *b = vlc_uint8( (y + b_add) >> SCALEBITS );
357 #undef FIX
358 #undef ONE_HALF
359 #undef SCALEBITS
360 }
361
362 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
363                                int r, int g, int b )
364 {
365     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
366     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
367     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
368 }
369
370 /***********************************************************************
371  * YUVA
372  ***********************************************************************/
373 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
374                        picture_t *p_dst_orig, picture_t *p_src,
375                        int i_x_offset, int i_y_offset,
376                        int i_width, int i_height, int i_alpha )
377 {
378     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
379     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
380     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
381     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
382     uint8_t *p_trans;
383     int i_x, i_y, i_trans = 0;
384     bool b_even_scanline = i_y_offset % 2;
385
386     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
387     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
388               p_filter->fmt_out.video.i_x_offset +
389               p_dst->p[Y_PLANE].i_pitch *
390               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
391     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
392               p_filter->fmt_out.video.i_x_offset/2 +
393               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
394               p_dst->p[U_PLANE].i_pitch;
395     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
396               p_filter->fmt_out.video.i_x_offset/2 +
397               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
398               p_dst->p[V_PLANE].i_pitch;
399
400     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
401     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
402                p_filter->fmt_out.video.i_x_offset +
403                p_dst_orig->p[Y_PLANE].i_pitch *
404                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
405     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
406                p_filter->fmt_out.video.i_x_offset/2 +
407                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
408                p_dst_orig->p[U_PLANE].i_pitch;
409     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
410                p_filter->fmt_out.video.i_x_offset/2 +
411                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
412                p_dst_orig->p[V_PLANE].i_pitch;
413
414     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
415     p_src2_y = p_src->p[Y_PLANE].p_pixels +
416                p_filter->fmt_in.video.i_x_offset +
417                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
418     p_src2_u = p_src->p[U_PLANE].p_pixels +
419                p_filter->fmt_in.video.i_x_offset/2 +
420                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
421     p_src2_v = p_src->p[V_PLANE].p_pixels +
422                p_filter->fmt_in.video.i_x_offset/2 +
423                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
424
425     p_trans = p_src->p[A_PLANE].p_pixels +
426               p_filter->fmt_in.video.i_x_offset +
427               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
428
429     /* Draw until we reach the bottom of the subtitle */
430     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
431          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
432          p_src2_y += i_src2_pitch,
433          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
434          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
435          p_src2_u += i_src2_pitch,
436          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
437          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
438          p_src2_v += i_src2_pitch )
439     {
440         b_even_scanline = !b_even_scanline;
441
442         /* Draw until we reach the end of the line */
443         for( i_x = 0; i_x < i_width; i_x++ )
444         {
445             if( p_trans )
446                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
447
448             if( !i_trans )
449                 continue;
450
451             /* Blending */
452             p_dst_y[i_x] = vlc_blend( p_src2_y[i_x], p_src1_y[i_x], i_trans );
453             if( b_even_scanline && i_x % 2 == 0 )
454             {
455                 p_dst_u[i_x/2] = vlc_blend( p_src2_u[i_x], p_src1_u[i_x/2], i_trans );
456                 p_dst_v[i_x/2] = vlc_blend( p_src2_v[i_x], p_src1_v[i_x/2], i_trans );
457             }
458         }
459     }
460 }
461
462 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
463                       picture_t *p_dst_orig, picture_t *p_src,
464                       int i_x_offset, int i_y_offset,
465                       int i_width, int i_height, int i_alpha )
466 {
467     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
468     uint8_t *p_dst, *p_src1, *p_src2_y;
469     uint8_t *p_src2_u, *p_src2_v;
470     uint8_t *p_trans;
471     int i_x, i_y, i_pix_pitch, i_trans = 0;
472     int r, g, b;
473
474     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
475     i_dst_pitch = p_dst_pic->p->i_pitch;
476     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
477             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
478             p_dst_pic->p->i_pitch *
479             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
480
481     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
482     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
483                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
484                p_dst_orig->p->i_pitch *
485                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
486
487     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
488     p_src2_y = p_src->p[Y_PLANE].p_pixels +
489                p_filter->fmt_in.video.i_x_offset +
490                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
491     p_src2_u = p_src->p[U_PLANE].p_pixels +
492                p_filter->fmt_in.video.i_x_offset/2 +
493                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
494     p_src2_v = p_src->p[V_PLANE].p_pixels +
495                p_filter->fmt_in.video.i_x_offset/2 +
496                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
497
498     p_trans = p_src->p[A_PLANE].p_pixels +
499               p_filter->fmt_in.video.i_x_offset +
500               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
501
502     /* Draw until we reach the bottom of the subtitle */
503     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
504          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
505          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
506          p_src2_v += i_src2_pitch )
507     {
508         /* Draw until we reach the end of the line */
509         for( i_x = 0; i_x < i_width; i_x++ )
510         {
511             if( p_trans )
512                 i_trans = ( p_trans[i_x] * i_alpha ) / 255;
513             if( !i_trans )
514                 continue;
515
516             /* Blending */
517             /* FIXME: do the blending
518              * FIXME use rgb shift (when present) */
519             yuv_to_rgb( &r, &g, &b,
520                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
521
522     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
523         }
524     }
525 }
526
527 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
528                       picture_t *p_dst_orig, picture_t *p_src,
529                       int i_x_offset, int i_y_offset,
530                       int i_width, int i_height, int i_alpha )
531 {
532     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
533     uint8_t *p_dst, *p_src1, *p_src2_y;
534     uint8_t *p_src2_u, *p_src2_v;
535     uint8_t *p_trans;
536     int i_x, i_y, i_pix_pitch, i_trans = 0;
537     int r, g, b;
538
539     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
540     i_dst_pitch = p_dst_pic->p->i_pitch;
541     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
542             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
543             p_dst_pic->p->i_pitch *
544             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
545
546     i_src1_pitch = p_dst_orig->p->i_pitch;
547     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
548                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
549                p_dst_orig->p->i_pitch *
550                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
551
552     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
553     p_src2_y = p_src->p[Y_PLANE].p_pixels +
554                p_filter->fmt_in.video.i_x_offset +
555                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
556     p_src2_u = p_src->p[U_PLANE].p_pixels +
557                p_filter->fmt_in.video.i_x_offset/2 +
558                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
559     p_src2_v = p_src->p[V_PLANE].p_pixels +
560                p_filter->fmt_in.video.i_x_offset/2 +
561                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
562
563     p_trans = p_src->p[A_PLANE].p_pixels +
564               p_filter->fmt_in.video.i_x_offset +
565               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
566
567     if( (i_pix_pitch == 4)
568      && (((((intptr_t)p_dst)|((intptr_t)p_src1)|i_dst_pitch|i_src1_pitch)
569           & 3) == 0) )
570     {
571         /*
572         ** if picture pixels are 32 bits long and lines addresses are 32 bit
573         ** aligned, optimize rendering
574         */
575         uint32_t *p32_dst = (uint32_t *)p_dst;
576         uint32_t i32_dst_pitch = (uint32_t)(i_dst_pitch>>2);
577         uint32_t *p32_src1 = (uint32_t *)p_src1;
578         uint32_t i32_src1_pitch = (uint32_t)(i_src1_pitch>>2);
579
580         int i_rshift, i_gshift, i_bshift;
581         uint32_t i_rmask, i_gmask, i_bmask;
582
583         if( p_dst_pic->p_heap )
584         {
585             i_rmask = p_dst_pic->p_heap->i_rmask;
586             i_gmask = p_dst_pic->p_heap->i_gmask;
587             i_bmask = p_dst_pic->p_heap->i_bmask;
588             i_rshift = p_dst_pic->p_heap->i_lrshift;
589             i_gshift = p_dst_pic->p_heap->i_lgshift;
590             i_bshift = p_dst_pic->p_heap->i_lbshift;
591         }
592         else
593         {
594             i_rmask = p_dst_pic->format.i_rmask;
595             i_gmask = p_dst_pic->format.i_gmask;
596             i_bmask = p_dst_pic->format.i_bmask;
597
598             if( (i_rmask == 0x00FF0000)
599              && (i_gmask == 0x0000FF00)
600              && (i_bmask == 0x000000FF) )
601             {
602                 /* X8R8G8B8 pixel layout */
603                 i_rshift = 16;
604                 i_bshift = 8;
605                 i_gshift = 0;
606             }
607             else if( (i_rmask == 0xFF000000)
608                   && (i_gmask == 0x00FF0000)
609                   && (i_bmask == 0x0000FF00) )
610             {
611                 /* R8G8B8X8 pixel layout */
612                 i_rshift = 24;
613                 i_bshift = 16;
614                 i_gshift = 8;
615             }
616             else
617             {
618                 goto slower;
619             }
620         }
621         /* Draw until we reach the bottom of the subtitle */
622         for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
623              p32_dst += i32_dst_pitch, p32_src1 += i32_src1_pitch,
624              p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
625              p_src2_v += i_src2_pitch )
626         {
627             /* Draw until we reach the end of the line */
628             for( i_x = 0; i_x < i_width; i_x++ )
629             {
630                 if( p_trans )
631                     i_trans = ( p_trans[i_x] * i_alpha ) / 255;
632                 if( !i_trans )
633                     continue;
634
635                 if( i_trans == MAX_TRANS )
636                 {
637                     /* Completely opaque. Completely overwrite underlying pixel */
638                     yuv_to_rgb( &r, &g, &b,
639                                 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
640
641                     p32_dst[i_x] = (r<<i_rshift) |
642                                    (g<<i_gshift) |
643                                    (b<<i_bshift);
644                 }
645                 else
646                 {
647                     /* Blending */
648                     uint32_t i_pix_src1 = p32_src1[i_x];
649                     yuv_to_rgb( &r, &g, &b,
650                                 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
651
652                     p32_dst[i_x] = ( vlc_blend( r, (i_pix_src1 & i_rmask)>>i_rshift, i_trans ) << i_rshift ) |
653                                    ( vlc_blend( g, (i_pix_src1 & i_gmask)>>i_gshift, i_trans ) << i_gshift ) |
654                                    ( vlc_blend( b, (i_pix_src1 & i_bmask)>>i_bshift, i_trans ) << i_bshift );
655                 }
656             }
657         }
658     }
659     else
660     {
661         int i_rindex, i_bindex, i_gindex;
662         uint32_t i_rmask, i_gmask, i_bmask;
663
664         slower:
665
666         i_rmask = p_dst_pic->format.i_rmask;
667         i_gmask = p_dst_pic->format.i_gmask;
668         i_bmask = p_dst_pic->format.i_bmask;
669
670         /*
671         ** quick and dirty way to get byte index from mask
672         ** will only work correctly if mask are 8 bit aligned
673         ** and are 8 bit long
674         */
675 #ifdef WORDS_BIGENDIAN
676         i_rindex = ((i_rmask>>16) & 1)
677                  | ((i_rmask>>8) & 2)
678                  | ((i_rmask) & 3);
679         i_gindex = ((i_gmask>>16) & 1)
680                  | ((i_gmask>>8) & 2)
681                  | ((i_gmask) & 3);
682         i_bindex = ((i_bmask>>16) & 1)
683                  | ((i_bmask>>8) & 2)
684                  | ((i_bmask) & 3);
685 #else
686         i_rindex = ((i_rmask>>24) & 3)
687                  | ((i_rmask>>16) & 2)
688                  | ((i_rmask>>8) & 1);
689         i_gindex = ((i_gmask>>24) & 3)
690                  | ((i_gmask>>16) & 2)
691                  | ((i_gmask>>8) & 1);
692         i_bindex = ((i_bmask>>24) & 3)
693                  | ((i_bmask>>16) & 2)
694                  | ((i_bmask>>8) & 1);
695 #endif
696
697         /* Draw until we reach the bottom of the subtitle */
698         for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
699              p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
700              p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
701              p_src2_v += i_src2_pitch )
702         {
703             /* Draw until we reach the end of the line */
704             for( i_x = 0; i_x < i_width; i_x++ )
705             {
706                 if( p_trans )
707                     i_trans = ( p_trans[i_x] * i_alpha ) / 255;
708                 if( !i_trans )
709                     continue;
710
711                 const int i_pos = i_x * i_pix_pitch;
712                 if( i_trans == MAX_TRANS )
713                 {
714
715                     /* Completely opaque. Completely overwrite underlying pixel */
716                     yuv_to_rgb( &r, &g, &b,
717                                 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
718
719                     p_dst[i_pos + i_rindex ] = r;
720                     p_dst[i_pos + i_gindex ] = g;
721                     p_dst[i_pos + i_bindex ] = b;
722                 }
723                 else
724                 {
725                     int i_rpos = i_pos + i_rindex;
726                     int i_gpos = i_pos + i_gindex;
727                     int i_bpos = i_pos + i_bindex;
728
729                     /* Blending */
730                     yuv_to_rgb( &r, &g, &b,
731                                 p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
732
733                     p_dst[i_rpos] = vlc_blend( r, p_src1[i_rpos], i_trans );
734                     p_dst[i_gpos] = vlc_blend( g, p_src1[i_gpos], i_trans );
735                     p_dst[i_bpos] = vlc_blend( b, p_src1[i_gpos], i_trans );
736                 }
737             }
738         }
739     }
740 }
741
742 static void BlendYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
743                             picture_t *p_dst_orig, picture_t *p_src,
744                             int i_x_offset, int i_y_offset,
745                             int i_width, int i_height, int i_alpha )
746 {
747     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
748     uint8_t *p_dst, *p_src1, *p_src2_y;
749     uint8_t *p_src2_u, *p_src2_v;
750     uint8_t *p_trans;
751     int i_x, i_y, i_pix_pitch, i_trans = 0;
752     bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
753     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
754
755     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
756     {
757         i_l_offset = 0;
758         i_u_offset = 1;
759         i_v_offset = 3;
760     }
761     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
762     {
763         i_l_offset = 1;
764         i_u_offset = 0;
765         i_v_offset = 2;
766     }
767     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
768     {
769         i_l_offset = 0;
770         i_u_offset = 3;
771         i_v_offset = 1;
772     }
773
774     i_pix_pitch = 2;
775     i_dst_pitch = p_dst_pic->p->i_pitch;
776     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
777             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
778             p_dst_pic->p->i_pitch *
779             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
780
781     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
782     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
783                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
784                p_dst_orig->p->i_pitch *
785                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
786
787     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
788     p_src2_y = p_src->p[Y_PLANE].p_pixels +
789                p_filter->fmt_in.video.i_x_offset +
790                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
791     p_src2_u = p_src->p[U_PLANE].p_pixels +
792                p_filter->fmt_in.video.i_x_offset/2 +
793                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
794     p_src2_v = p_src->p[V_PLANE].p_pixels +
795                p_filter->fmt_in.video.i_x_offset/2 +
796                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
797
798     p_trans = p_src->p[A_PLANE].p_pixels +
799               p_filter->fmt_in.video.i_x_offset +
800               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
801
802     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
803
804     /* Draw until we reach the bottom of the subtitle */
805     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
806          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
807          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
808          p_src2_v += i_src2_pitch )
809     {
810         /* Draw until we reach the end of the line */
811         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
812         {
813             i_trans = ( p_trans[i_x] * i_alpha ) / 255;
814             if( !i_trans )
815                 continue;
816
817             /* Blending */
818             p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_trans );
819             if( b_even )
820             {
821                 int i_u;
822                 int i_v;
823                 /* FIXME what's with 0xaa ? */
824                 if( p_trans[i_x+1] > 0xaa )
825                 {
826                     i_u = (p_src2_u[i_x]+p_src2_u[i_x+1])>>1;
827                     i_v = (p_src2_v[i_x]+p_src2_v[i_x+1])>>1;
828                 }
829                 else
830                 {
831                     i_u = p_src2_u[i_x];
832                     i_v = p_src2_v[i_x];
833                 }
834                 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_trans );
835                 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_trans );
836             }
837         }
838     }
839 }
840 /***********************************************************************
841  * I420, YV12
842  ***********************************************************************/
843 static void BlendI420I420( filter_t *p_filter, picture_t *p_dst,
844                            picture_t *p_dst_orig, picture_t *p_src,
845                            int i_x_offset, int i_y_offset,
846                            int i_width, int i_height, int i_alpha )
847 {
848     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
849     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
850     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
851     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
852     int i_x, i_y;
853     bool b_even_scanline = i_y_offset % 2;
854
855     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
856     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
857               p_filter->fmt_out.video.i_x_offset +
858               p_dst->p[Y_PLANE].i_pitch *
859               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
860     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
861               p_filter->fmt_out.video.i_x_offset/2 +
862               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
863               p_dst->p[U_PLANE].i_pitch;
864     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
865               p_filter->fmt_out.video.i_x_offset/2 +
866               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
867               p_dst->p[V_PLANE].i_pitch;
868
869     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
870     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
871                p_filter->fmt_out.video.i_x_offset +
872                p_dst_orig->p[Y_PLANE].i_pitch *
873                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
874     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
875                p_filter->fmt_out.video.i_x_offset/2 +
876                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
877                p_dst_orig->p[U_PLANE].i_pitch;
878     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
879                p_filter->fmt_out.video.i_x_offset/2 +
880                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
881                p_dst_orig->p[V_PLANE].i_pitch;
882
883     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
884     p_src2_y = p_src->p[Y_PLANE].p_pixels +
885                p_filter->fmt_in.video.i_x_offset +
886                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
887     p_src2_u = p_src->p[U_PLANE].p_pixels +
888                p_filter->fmt_in.video.i_x_offset/2 +
889                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
890     p_src2_v = p_src->p[V_PLANE].p_pixels +
891                p_filter->fmt_in.video.i_x_offset/2 +
892                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
893
894     /* Draw until we reach the bottom of the subtitle */
895     for( i_y = 0; i_y < i_height; i_y++,
896          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
897          p_src2_y += i_src2_pitch )
898     {
899         if( b_even_scanline )
900         {
901             p_dst_u  += i_dst_pitch/2;
902             p_dst_v  += i_dst_pitch/2;
903             p_src1_u += i_src1_pitch/2;
904             p_src1_v += i_src1_pitch/2;
905         }
906         b_even_scanline = !b_even_scanline;
907
908         /* Draw until we reach the end of the line */
909         for( i_x = 0; i_x < i_width; i_x++ )
910         {
911             if( !i_alpha )
912                 continue;
913
914             /* Blending */
915             p_dst_y[i_x] = vlc_blend( p_src2_y[i_x], p_src1_y[i_x], i_alpha );
916             if( b_even_scanline && i_x % 2 == 0 )
917             {
918                 p_dst_u[i_x/2] = vlc_blend( p_src2_u[i_x/2], p_src1_u[i_x/2], i_alpha );
919                 p_dst_v[i_x/2] = vlc_blend( p_src2_v[i_x/2], p_src1_v[i_x/2], i_alpha );
920             }
921         }
922         if( i_y%2 == 1 )
923         {
924             p_src2_u += i_src2_pitch/2;
925             p_src2_v += i_src2_pitch/2;
926         }
927     }
928 }
929 static void BlendI420I420_no_alpha( filter_t *p_filter, picture_t *p_dst,
930                                     picture_t *p_dst_orig, picture_t *p_src,
931                                     int i_x_offset, int i_y_offset,
932                                     int i_width, int i_height )
933 {
934     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
935     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
936     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
937     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
938     int i_y;
939     bool b_even_scanline = i_y_offset % 2;
940
941     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
942     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
943               p_filter->fmt_out.video.i_x_offset +
944               p_dst->p[Y_PLANE].i_pitch *
945               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
946     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
947               p_filter->fmt_out.video.i_x_offset/2 +
948               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
949               p_dst->p[U_PLANE].i_pitch;
950     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
951               p_filter->fmt_out.video.i_x_offset/2 +
952               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
953               p_dst->p[V_PLANE].i_pitch;
954
955     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
956     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
957                p_filter->fmt_out.video.i_x_offset +
958                p_dst_orig->p[Y_PLANE].i_pitch *
959                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
960     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
961                p_filter->fmt_out.video.i_x_offset/2 +
962                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
963                p_dst_orig->p[U_PLANE].i_pitch;
964     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
965                p_filter->fmt_out.video.i_x_offset/2 +
966                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
967                p_dst_orig->p[V_PLANE].i_pitch;
968
969     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
970     p_src2_y = p_src->p[Y_PLANE].p_pixels +
971                p_filter->fmt_in.video.i_x_offset +
972                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
973     p_src2_u = p_src->p[U_PLANE].p_pixels +
974                p_filter->fmt_in.video.i_x_offset/2 +
975                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
976     p_src2_v = p_src->p[V_PLANE].p_pixels +
977                p_filter->fmt_in.video.i_x_offset/2 +
978                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
979
980     i_width &= ~1;
981
982     /* Draw until we reach the bottom of the subtitle */
983     for( i_y = 0; i_y < i_height; i_y++,
984          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
985          p_src2_y += i_src2_pitch )
986     {
987         /* Completely opaque. Completely overwrite underlying pixel */
988         vlc_memcpy( p_dst_y, p_src2_y, i_width );
989         if( b_even_scanline )
990         {
991             p_dst_u  += i_dst_pitch/2;
992             p_dst_v  += i_dst_pitch/2;
993             p_src1_u += i_src1_pitch/2;
994             p_src1_v += i_src1_pitch/2;
995         }
996         else
997         {
998             vlc_memcpy( p_dst_u, p_src2_u, i_width/2 );
999             vlc_memcpy( p_dst_v, p_src2_v, i_width/2 );
1000         }
1001         b_even_scanline = !b_even_scanline;
1002         if( i_y%2 == 1 )
1003         {
1004             p_src2_u += i_src2_pitch/2;
1005             p_src2_v += i_src2_pitch/2;
1006         }
1007     }
1008
1009     return;
1010 }
1011
1012 static void BlendI420R16( filter_t *p_filter, picture_t *p_dst_pic,
1013                           picture_t *p_dst_orig, picture_t *p_src,
1014                           int i_x_offset, int i_y_offset,
1015                           int i_width, int i_height, int i_alpha )
1016 {
1017     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1018     uint8_t *p_dst, *p_src1, *p_src2_y;
1019     uint8_t *p_src2_u, *p_src2_v;
1020     int i_x, i_y, i_pix_pitch;
1021     int r, g, b;
1022
1023     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1024     i_dst_pitch = p_dst_pic->p->i_pitch;
1025     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1026             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1027             p_dst_pic->p->i_pitch *
1028             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1029
1030     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1031     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1032                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1033                p_dst_orig->p->i_pitch *
1034                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1035
1036     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1037     p_src2_y = p_src->p[Y_PLANE].p_pixels +
1038                p_filter->fmt_in.video.i_x_offset +
1039                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1040     p_src2_u = p_src->p[U_PLANE].p_pixels +
1041                p_filter->fmt_in.video.i_x_offset/2 +
1042                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1043     p_src2_v = p_src->p[V_PLANE].p_pixels +
1044                p_filter->fmt_in.video.i_x_offset/2 +
1045                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1046
1047     /* Draw until we reach the bottom of the subtitle */
1048     for( i_y = 0; i_y < i_height; i_y++,
1049          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1050          p_src2_y += i_src2_pitch )
1051     {
1052         /* Draw until we reach the end of the line */
1053         for( i_x = 0; i_x < i_width; i_x++ )
1054         {
1055             if( i_alpha == MAX_TRANS )
1056             {
1057                 /* Completely opaque. Completely overwrite underlying pixel */
1058                 yuv_to_rgb( &r, &g, &b,
1059                             p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1060
1061     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1062                 continue;
1063             }
1064
1065             /* Blending */
1066             /* FIXME: do the blending
1067              * FIXME use rgb shifts */
1068             yuv_to_rgb( &r, &g, &b,
1069                         p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1070
1071     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1072         }
1073         if( i_y%2 == 1 )
1074         {
1075             p_src2_u += i_src2_pitch/2;
1076             p_src2_v += i_src2_pitch/2;
1077         }
1078     }
1079 }
1080
1081 static void BlendI420R24( filter_t *p_filter, picture_t *p_dst_pic,
1082                           picture_t *p_dst_orig, picture_t *p_src,
1083                           int i_x_offset, int i_y_offset,
1084                           int i_width, int i_height, int i_alpha )
1085 {
1086     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1087     uint8_t *p_dst, *p_src1, *p_src2_y;
1088     uint8_t *p_src2_u, *p_src2_v;
1089     int i_x, i_y, i_pix_pitch;
1090     int r, g, b;
1091
1092     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1093     i_dst_pitch = p_dst_pic->p->i_pitch;
1094     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1095             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1096             p_dst_pic->p->i_pitch *
1097             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1098
1099     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1100     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1101                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1102                p_dst_orig->p->i_pitch *
1103                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1104
1105     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1106     p_src2_y = p_src->p[Y_PLANE].p_pixels +
1107                p_filter->fmt_in.video.i_x_offset +
1108                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1109     p_src2_u = p_src->p[U_PLANE].p_pixels +
1110                p_filter->fmt_in.video.i_x_offset/2 +
1111                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1112     p_src2_v = p_src->p[V_PLANE].p_pixels +
1113                p_filter->fmt_in.video.i_x_offset/2 +
1114                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1115
1116     /* Draw until we reach the bottom of the subtitle */
1117     for( i_y = 0; i_y < i_height; i_y++,
1118          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1119          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1120          p_src2_v += i_src2_pitch )
1121     {
1122         /* Draw until we reach the end of the line */
1123         for( i_x = 0; i_x < i_width; i_x++ )
1124         {
1125             if( !i_alpha )
1126                 continue;
1127
1128             /* Blending */
1129             yuv_to_rgb( &r, &g, &b,
1130                         p_src2_y[i_x], p_src2_u[i_x/2], p_src2_v[i_x/2] );
1131
1132             p_dst[i_x * i_pix_pitch + 0] = vlc_blend( r, p_src1[i_x * i_pix_pitch + 0], i_alpha );
1133             p_dst[i_x * i_pix_pitch + 1] = vlc_blend( g, p_src1[i_x * i_pix_pitch + 1], i_alpha );
1134             p_dst[i_x * i_pix_pitch + 2] = vlc_blend( b, p_src1[i_x * i_pix_pitch + 2], i_alpha );
1135         }
1136         if( i_y%2 == 1 )
1137         {
1138             p_src2_u += i_src2_pitch/2;
1139             p_src2_v += i_src2_pitch/2;
1140         }
1141     }
1142 }
1143
1144 static void BlendI420YUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1145                                 picture_t *p_dst_orig, picture_t *p_src,
1146                                 int i_x_offset, int i_y_offset,
1147                                 int i_width, int i_height, int i_alpha )
1148 {
1149     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1150     uint8_t *p_dst, *p_src1, *p_src2_y;
1151     uint8_t *p_src2_u, *p_src2_v;
1152     int i_x, i_y, i_pix_pitch;
1153     bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1154     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1155
1156     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1157     {
1158         i_l_offset = 0;
1159         i_u_offset = 1;
1160         i_v_offset = 3;
1161     }
1162     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1163     {
1164         i_l_offset = 1;
1165         i_u_offset = 0;
1166         i_v_offset = 2;
1167     }
1168     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1169     {
1170         i_l_offset = 0;
1171         i_u_offset = 3;
1172         i_v_offset = 1;
1173     }
1174
1175     i_pix_pitch = 2;
1176     i_dst_pitch = p_dst_pic->p->i_pitch;
1177     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1178             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1179             p_dst_pic->p->i_pitch *
1180             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1181
1182     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1183     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1184                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1185                p_dst_orig->p->i_pitch *
1186                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1187
1188     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
1189     p_src2_y = p_src->p[Y_PLANE].p_pixels +
1190                p_filter->fmt_in.video.i_x_offset +
1191                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
1192     p_src2_u = p_src->p[U_PLANE].p_pixels +
1193                p_filter->fmt_in.video.i_x_offset/2 +
1194                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1195     p_src2_v = p_src->p[V_PLANE].p_pixels +
1196                p_filter->fmt_in.video.i_x_offset/2 +
1197                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
1198
1199     i_width &= ~1; /* Needs to be a multiple of 2 */
1200
1201     /* Draw until we reach the bottom of the subtitle */
1202     for( i_y = 0; i_y < i_height; i_y++,
1203          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1204          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
1205          p_src2_v += i_src2_pitch )
1206     {
1207         /* Draw until we reach the end of the line */
1208         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1209         {
1210             if( !i_alpha )
1211                 continue;
1212
1213             /* Blending */
1214             p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_src2_y[i_x], p_src1[i_x * 2 + i_l_offset], i_alpha );
1215             if( b_even )
1216             {
1217                 uint16_t i_u = p_src2_u[i_x/2];
1218                 uint16_t i_v = p_src2_v[i_x/2];
1219                 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_alpha );
1220                 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_alpha );
1221             }
1222         }
1223         if( i_y%2 == 1 )
1224         {
1225             p_src2_u += i_src2_pitch/2;
1226             p_src2_v += i_src2_pitch/2;
1227         }
1228     }
1229 }
1230
1231 /***********************************************************************
1232  * YUVP
1233  ***********************************************************************/
1234 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
1235                           picture_t *p_dst_orig, picture_t *p_src,
1236                           int i_x_offset, int i_y_offset,
1237                           int i_width, int i_height, int i_alpha )
1238 {
1239     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1240     uint8_t *p_src1_y, *p_src2, *p_dst_y;
1241     uint8_t *p_src1_u, *p_dst_u;
1242     uint8_t *p_src1_v, *p_dst_v;
1243     int i_x, i_y, i_trans;
1244     bool b_even_scanline = i_y_offset % 2;
1245
1246     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1247     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1248               p_filter->fmt_out.video.i_x_offset +
1249               p_dst->p[Y_PLANE].i_pitch *
1250               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1251     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1252               p_filter->fmt_out.video.i_x_offset/2 +
1253               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1254               p_dst->p[U_PLANE].i_pitch;
1255     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1256               p_filter->fmt_out.video.i_x_offset/2 +
1257               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1258               p_dst->p[V_PLANE].i_pitch;
1259
1260     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1261     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1262                p_filter->fmt_out.video.i_x_offset +
1263                p_dst_orig->p[Y_PLANE].i_pitch *
1264                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1265     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1266                p_filter->fmt_out.video.i_x_offset/2 +
1267                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1268                p_dst_orig->p[U_PLANE].i_pitch;
1269     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1270                p_filter->fmt_out.video.i_x_offset/2 +
1271                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1272                p_dst_orig->p[V_PLANE].i_pitch;
1273
1274     i_src2_pitch = p_src->p->i_pitch;
1275     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1276              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1277
1278     const uint8_t *p_trans = p_src2;
1279 #define p_pal p_filter->fmt_in.video.p_palette->palette
1280
1281     /* Draw until we reach the bottom of the subtitle */
1282     for( i_y = 0; i_y < i_height; i_y++,
1283          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1284          p_src2 += i_src2_pitch,
1285          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1286          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1287          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1288          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
1289     {
1290         b_even_scanline = !b_even_scanline;
1291
1292         /* Draw until we reach the end of the line */
1293         for( i_x = 0; i_x < i_width; i_x++ )
1294         {
1295             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1296             if( !i_trans )
1297                 continue;
1298
1299             /* Blending */
1300             p_dst_y[i_x] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1_y[i_x], i_trans );
1301             if( b_even_scanline && ((i_x % 2) == 0) )
1302             {
1303                 p_dst_u[i_x/2] = vlc_blend( p_pal[p_src2[i_x]][1], p_src1_u[i_x/2], i_trans );
1304                 p_dst_v[i_x/2] = vlc_blend( p_pal[p_src2[i_x]][2], p_src1_v[i_x/2], i_trans );
1305             }
1306         }
1307     }
1308 #undef p_pal
1309 }
1310
1311 static void BlendPalYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1312                                picture_t *p_dst_orig, picture_t *p_src,
1313                                int i_x_offset, int i_y_offset,
1314                                int i_width, int i_height, int i_alpha )
1315 {
1316     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1317     uint8_t *p_src1, *p_src2, *p_dst;
1318     int i_x, i_y, i_pix_pitch, i_trans;
1319     bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1320     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1321
1322     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1323     {
1324         i_l_offset = 0;
1325         i_u_offset = 1;
1326         i_v_offset = 3;
1327     }
1328     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1329     {
1330         i_l_offset = 1;
1331         i_u_offset = 0;
1332         i_v_offset = 2;
1333     }
1334     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1335     {
1336         i_l_offset = 0;
1337         i_u_offset = 3;
1338         i_v_offset = 1;
1339     }
1340
1341     i_pix_pitch = 2;
1342     i_dst_pitch = p_dst_pic->p->i_pitch;
1343     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1344             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1345             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1346
1347     i_src1_pitch = p_dst_orig->p->i_pitch;
1348     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1349              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1350              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1351
1352     i_src2_pitch = p_src->p->i_pitch;
1353     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1354              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1355
1356     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1357
1358     const uint8_t *p_trans = p_src2;
1359 #define p_pal p_filter->fmt_in.video.p_palette->palette
1360
1361     /* Draw until we reach the bottom of the subtitle */
1362     for( i_y = 0; i_y < i_height; i_y++,
1363          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1364     {
1365         /* Draw until we reach the end of the line */
1366         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1367         {
1368             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1369             if( !i_trans )
1370                 continue;
1371
1372             /* Blending */
1373             p_dst[i_x * 2 + i_l_offset] = vlc_blend( p_pal[p_src2[i_x]][0], p_src1[i_x * 2 + i_l_offset], i_trans );
1374             if( b_even )
1375             {
1376                 uint16_t i_u;
1377                 uint16_t i_v;
1378                 if( p_trans[i_x+1] > 0xaa )
1379                 {
1380                     i_u = (p_pal[p_src2[i_x]][1] + p_pal[p_src2[i_x+1]][1]) >> 1;
1381                     i_v = (p_pal[p_src2[i_x]][2] + p_pal[p_src2[i_x+1]][2]) >> 1;
1382                 }
1383                 else
1384                 {
1385                     i_u = p_pal[p_src2[i_x]][1];
1386                     i_v = p_pal[p_src2[i_x]][2];
1387                 }
1388
1389                 p_dst[i_x * 2 + i_u_offset] = vlc_blend( i_u, p_src1[i_x * 2 + i_u_offset], i_trans );
1390                 p_dst[i_x * 2 + i_v_offset] = vlc_blend( i_v, p_src1[i_x * 2 + i_v_offset], i_trans );
1391             }
1392         }
1393     }
1394 #undef p_pal
1395 }
1396
1397 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
1398                         picture_t *p_dst_orig, picture_t *p_src,
1399                         int i_x_offset, int i_y_offset,
1400                         int i_width, int i_height, int i_alpha )
1401 {
1402     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1403     uint8_t *p_src1, *p_src2, *p_dst;
1404     int i_x, i_y, i_pix_pitch, i_trans;
1405     int r, g, b;
1406     video_palette_t rgbpalette;
1407
1408     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1409     i_dst_pitch = p_dst_pic->p->i_pitch;
1410     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
1411             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
1412             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1413
1414     i_src1_pitch = p_dst_orig->p->i_pitch;
1415     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
1416              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
1417              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1418
1419     i_src2_pitch = p_src->p->i_pitch;
1420     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
1421              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
1422
1423     const uint8_t *p_trans = p_src2;
1424 #define p_pal p_filter->fmt_in.video.p_palette->palette
1425 #define rgbpal rgbpalette.palette
1426
1427     /* Convert palette first */
1428     for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
1429          i_y < 256; i_y++ )
1430     {
1431         yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
1432
1433         if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1434         {
1435             *(uint16_t *)rgbpal[i_y] =
1436                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
1437         }
1438         else
1439         {
1440             rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
1441         }
1442     }
1443
1444     /* Draw until we reach the bottom of the subtitle */
1445     for( i_y = 0; i_y < i_height; i_y++,
1446          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1447     {
1448         /* Draw until we reach the end of the line */
1449         for( i_x = 0; i_x < i_width; i_x++ )
1450         {
1451             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
1452             if( !i_trans )
1453                 continue;
1454
1455             if( i_trans == MAX_TRANS ||
1456                 p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
1457             {
1458                 /* FIXME implement blending for RV16 */
1459                 /* Completely opaque. Completely overwrite underlying pixel */
1460                 p_dst[i_x * i_pix_pitch]     = rgbpal[p_src2[i_x]][0];
1461                 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
1462                 if( p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','1','6') )
1463                     p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
1464                 continue;
1465             }
1466
1467             /* Blending */
1468             p_dst[i_x * i_pix_pitch + 0] = vlc_blend( rgbpal[p_src2[i_x]][0], p_src1[i_x * i_pix_pitch + 0], i_trans );
1469             p_dst[i_x * i_pix_pitch + 1] = vlc_blend( rgbpal[p_src2[i_x]][1], p_src1[i_x * i_pix_pitch + 1], i_trans );
1470             p_dst[i_x * i_pix_pitch + 2] = vlc_blend( rgbpal[p_src2[i_x]][2], p_src1[i_x * i_pix_pitch + 2], i_trans );
1471         }
1472     }
1473
1474 #undef p_pal
1475 #undef rgbpal
1476 }
1477
1478 /***********************************************************************
1479  * RGBA
1480  ***********************************************************************/
1481 static void BlendRGBAI420( filter_t *p_filter, picture_t *p_dst,
1482                            picture_t *p_dst_orig, picture_t *p_src,
1483                            int i_x_offset, int i_y_offset,
1484                            int i_width, int i_height, int i_alpha )
1485 {
1486     int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1487     uint8_t *p_src1_y, *p_dst_y;
1488     uint8_t *p_src1_u, *p_dst_u;
1489     uint8_t *p_src1_v, *p_dst_v;
1490     uint8_t *p_src2;
1491     int i_x, i_y, i_trans;
1492     uint8_t y, u, v;
1493
1494     bool b_even_scanline = i_y_offset % 2;
1495
1496     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
1497     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
1498               p_filter->fmt_out.video.i_x_offset +
1499               p_dst->p[Y_PLANE].i_pitch *
1500               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1501     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
1502               p_filter->fmt_out.video.i_x_offset/2 +
1503               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1504               p_dst->p[U_PLANE].i_pitch;
1505     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
1506               p_filter->fmt_out.video.i_x_offset/2 +
1507               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1508               p_dst->p[V_PLANE].i_pitch;
1509
1510     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1511     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
1512                p_filter->fmt_out.video.i_x_offset +
1513                p_dst_orig->p[Y_PLANE].i_pitch *
1514                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1515     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
1516                p_filter->fmt_out.video.i_x_offset/2 +
1517                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1518                p_dst_orig->p[U_PLANE].i_pitch;
1519     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
1520                p_filter->fmt_out.video.i_x_offset/2 +
1521                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
1522                p_dst_orig->p[V_PLANE].i_pitch;
1523
1524     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1525     i_src2_pitch = p_src->p->i_pitch;
1526     p_src2 = p_src->p->p_pixels +
1527              p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1528              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1529
1530
1531     /* Draw until we reach the bottom of the subtitle */
1532     for( i_y = 0; i_y < i_height; i_y++,
1533          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
1534          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
1535          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
1536          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
1537          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
1538          p_src2 += i_src2_pitch )
1539     {
1540         b_even_scanline = !b_even_scanline;
1541
1542         /* Draw until we reach the end of the line */
1543         for( i_x = 0; i_x < i_width; i_x++ )
1544         {
1545 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1546 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1547 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1548             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1549             if( !i_trans )
1550                 continue;
1551
1552             /* Blending */
1553             rgb_to_yuv( &y, &u, &v, R, G, B );
1554
1555             p_dst_y[i_x] = vlc_blend( y, p_src1_y[i_x], i_trans );
1556             if( b_even_scanline && i_x % 2 == 0 )
1557             {
1558                 p_dst_u[i_x/2] = vlc_blend( u, p_src1_u[i_x/2], i_trans );
1559                 p_dst_v[i_x/2] = vlc_blend( v, p_src1_v[i_x/2], i_trans );
1560             }
1561 #undef      R
1562 #undef      G
1563 #undef      B
1564         }
1565     }
1566 }
1567
1568 static void BlendRGBAR24( filter_t *p_filter, picture_t *p_dst_pic,
1569                           picture_t *p_dst_orig, picture_t *p_src,
1570                           int i_x_offset, int i_y_offset,
1571                           int i_width, int i_height, int i_alpha )
1572 {
1573     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1574     uint8_t *p_dst, *p_src1, *p_src2;
1575     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1576
1577     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1578     i_dst_pitch = p_dst_pic->p->i_pitch;
1579     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1580             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1581             p_dst_pic->p->i_pitch *
1582             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1583
1584     i_src1_pitch = p_dst_orig->p->i_pitch;
1585     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1586              p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1587              p_dst_orig->p->i_pitch *
1588              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1589
1590     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1591     i_src2_pitch = p_src->p->i_pitch;
1592     p_src2 = p_src->p->p_pixels +
1593              p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1594              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1595
1596     /* Draw until we reach the bottom of the subtitle */
1597     for( i_y = 0; i_y < i_height; i_y++,
1598          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1599     {
1600         /* Draw until we reach the end of the line */
1601         for( i_x = 0; i_x < i_width; i_x++ )
1602         {
1603 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1604 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1605 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1606             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1607             if( !i_trans )
1608                 continue;
1609
1610             /* Blending */
1611             p_dst[i_x * i_pix_pitch + 0] = vlc_blend( R, p_src1[i_x * i_pix_pitch + 0], i_trans );
1612             p_dst[i_x * i_pix_pitch + 1] = vlc_blend( G, p_src1[i_x * i_pix_pitch + 1], i_trans );
1613             p_dst[i_x * i_pix_pitch + 2] = vlc_blend( B, p_src1[i_x * i_pix_pitch + 2], i_trans );
1614 #undef      R
1615 #undef      G
1616 #undef      B
1617         }
1618     }
1619 }
1620
1621 static void BlendRGBAR16( filter_t *p_filter, picture_t *p_dst_pic,
1622                           picture_t *p_dst_orig, picture_t *p_src,
1623                           int i_x_offset, int i_y_offset,
1624                           int i_width, int i_height, int i_alpha )
1625 {
1626     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
1627     uint8_t *p_dst, *p_src1, *p_src2;
1628     int i_x, i_y, i_pix_pitch, i_trans, i_src_pix_pitch;
1629     uint16_t i_pix;
1630
1631     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
1632     i_dst_pitch = p_dst_pic->p->i_pitch;
1633     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1634             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1635             p_dst_pic->p->i_pitch *
1636             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1637
1638     i_src1_pitch = p_dst_orig->p->i_pitch;
1639     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1640              p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1641              p_dst_orig->p->i_pitch *
1642              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1643
1644     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1645     i_src2_pitch = p_src->p->i_pitch;
1646     p_src2 = p_src->p->p_pixels +
1647              p_filter->fmt_in.video.i_x_offset * i_pix_pitch +
1648              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1649
1650     /* Draw until we reach the bottom of the subtitle */
1651     for( i_y = 0; i_y < i_height; i_y++,
1652          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
1653     {
1654         /* Draw until we reach the end of the line */
1655         for( i_x = 0; i_x < i_width; i_x++ )
1656         {
1657 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1658 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1659 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1660             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1661             if( !i_trans )
1662                 continue;
1663
1664             else if( i_trans == MAX_TRANS )
1665             {
1666                 /* Completely opaque. Completely overwrite underlying pixel */
1667                 *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) = ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3);
1668                 continue;
1669             }
1670
1671             /* Blending */
1672             i_pix = *((uint16_t *)(&p_dst[i_x * i_pix_pitch]));
1673             *((uint16_t *)(&p_dst[i_x * i_pix_pitch])) =
1674                 ( vlc_blend( R >> 3, ((i_pix         )>> 11), i_trans ) << 11 ) |
1675                 ( vlc_blend( G >> 2, ((i_pix & 0x07e0)>>  5), i_trans ) <<  5 ) |
1676                 ( vlc_blend( B >> 3, ((i_pix & 0x001f)     ), i_trans )       );
1677 #undef      R
1678 #undef      G
1679 #undef      B
1680         }
1681     }
1682 }
1683
1684 static void BlendRGBAYUVPacked( filter_t *p_filter, picture_t *p_dst_pic,
1685                                 picture_t *p_dst_orig, picture_t *p_src,
1686                                 int i_x_offset, int i_y_offset,
1687                                 int i_width, int i_height, int i_alpha )
1688 {
1689     int i_src1_pitch, i_src2_pitch, i_dst_pitch, i_src_pix_pitch;
1690     uint8_t *p_dst, *p_src1, *p_src2;
1691     uint8_t *p_trans;
1692     int i_x, i_y, i_pix_pitch, i_trans;
1693     bool b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
1694     int i_l_offset = 0, i_u_offset = 0, i_v_offset = 0;
1695     uint8_t y, u, v;
1696
1697     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
1698     {
1699         i_l_offset = 0;
1700         i_u_offset = 1;
1701         i_v_offset = 3;
1702     }
1703     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('U','Y','V','Y') )
1704     {
1705         i_l_offset = 1;
1706         i_u_offset = 0;
1707         i_v_offset = 2;
1708     }
1709     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','Y','U') )
1710     {
1711         i_l_offset = 0;
1712         i_u_offset = 3;
1713         i_v_offset = 1;
1714     }
1715
1716     i_pix_pitch = 2;
1717     i_dst_pitch = p_dst_pic->p->i_pitch;
1718     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
1719             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1720             p_dst_pic->p->i_pitch *
1721             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1722
1723     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
1724     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
1725                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
1726                p_dst_orig->p->i_pitch *
1727                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
1728
1729     i_src_pix_pitch = p_src->p->i_pixel_pitch;
1730     i_src2_pitch = p_src->p->i_pitch;
1731     p_src2 = p_src->p->p_pixels +
1732              p_filter->fmt_in.video.i_x_offset * i_src2_pitch +
1733              p_src->p->i_pitch * p_filter->fmt_in.video.i_y_offset;
1734
1735     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
1736
1737     /* Draw until we reach the bottom of the subtitle */
1738     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
1739          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
1740          p_src2 += i_src2_pitch )
1741     {
1742         /* Draw until we reach the end of the line */
1743         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
1744         {
1745 #define     R         ( p_src2[i_x * i_src_pix_pitch + 0] )
1746 #define     G         ( p_src2[i_x * i_src_pix_pitch + 1] )
1747 #define     B         ( p_src2[i_x * i_src_pix_pitch + 2] )
1748             i_trans = ( p_src2[i_x * i_src_pix_pitch + 3] * i_alpha ) / 255;
1749             if( !i_trans )
1750                 continue;
1751
1752             /* Blending */
1753             rgb_to_yuv( &y, &u, &v, R, G, B );
1754             p_dst[i_x * 2 + i_l_offset]     = vlc_blend( y, p_src1[i_x * 2 + i_l_offset], i_trans );
1755             if( b_even )
1756             {
1757                 p_dst[i_x * 2 + i_u_offset] = vlc_blend( u, p_src1[i_x * 2 + i_u_offset], i_trans );
1758                 p_dst[i_x * 2 + i_v_offset] = vlc_blend( v, p_src1[i_x * 2 + i_v_offset], i_trans );
1759             }
1760         }
1761     }
1762 }