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