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