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