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