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