]> git.sesse.net Git - vlc/blob - modules/video_filter/blend.c
* modules/video_filter/blend.c: portability fix.
[vlc] / modules / video_filter / blend.c
1 /*****************************************************************************
2  * blend.c: alpha blend 2 pictures together
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id$
6  *
7  * Author: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28 #include <vlc/decoder.h>
29 #include "vlc_filter.h"
30
31 /*****************************************************************************
32  * filter_sys_t : filter descriptor
33  *****************************************************************************/
34 struct filter_sys_t
35 {
36     int i_dummy;
37 };
38
39 /****************************************************************************
40  * Local prototypes
41  ****************************************************************************/
42 static int  OpenFilter ( vlc_object_t * );
43 static void CloseFilter( vlc_object_t * );
44
45 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
46                    int, int );
47 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
48                        int, int, int, int );
49 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
50                       int, int, int, int );
51 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
52                       int, int, int, int );
53 static void BlendYUY2( filter_t *, picture_t *, picture_t *, picture_t *,
54                        int, int, int, int );
55 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
56                           int, int, int, int );
57 static void BlendPalYUY2( filter_t *, picture_t *, picture_t *, picture_t *,
58                           int, int, int, int );
59 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
60                         int, int, int, int );
61
62 /*****************************************************************************
63  * Module descriptor
64  *****************************************************************************/
65 vlc_module_begin();
66     set_description( _("Video pictures blending") );
67     set_capability( "video blending", 100 );
68     set_callbacks( OpenFilter, CloseFilter );
69 vlc_module_end();
70
71 /*****************************************************************************
72  * OpenFilter: probe the filter and return score
73  *****************************************************************************/
74 static int OpenFilter( vlc_object_t *p_this )
75 {
76     filter_t *p_filter = (filter_t*)p_this;
77     filter_sys_t *p_sys;
78
79     /* Check if we can handle that format.
80      * We could try to use a chroma filter if we can't. */
81     if( ( p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','U','V','A') &&
82           p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','U','V','P') ) ||
83         ( p_filter->fmt_out.video.i_chroma != VLC_FOURCC('I','4','2','0') &&
84           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('Y','U','Y','2') &&
85           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('Y','V','1','2') &&
86           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','1','6') &&
87           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','2','4') &&
88           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','3','2') ) )
89     {
90         return VLC_EGENERIC;
91     }
92
93     /* Allocate the memory needed to store the decoder's structure */
94     if( ( p_filter->p_sys = p_sys =
95           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
96     {
97         msg_Err( p_filter, "out of memory" );
98         return VLC_EGENERIC;
99     }
100
101     /* Misc init */
102     p_filter->pf_video_blend = Blend;
103
104     msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
105              (char *)&p_filter->fmt_in.video.i_chroma,
106              (char *)&p_filter->fmt_out.video.i_chroma );
107
108
109     return VLC_SUCCESS;
110 }
111
112 /****************************************************************************
113  * Blend: the whole thing
114  ****************************************************************************
115  * This function is called just after the thread is launched.
116  ****************************************************************************/
117 static void Blend( filter_t *p_filter, picture_t *p_dst,
118                    picture_t *p_dst_orig, picture_t *p_src,
119                    int i_x_offset, int i_y_offset )
120 {
121     int i_width, i_height;
122
123     i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
124                     (int)p_filter->fmt_in.video.i_visible_width);
125
126     i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
127                      (int)p_filter->fmt_in.video.i_visible_height);
128
129     if( i_width <= 0 || i_height <= 0 ) return;
130
131     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
132         ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('I','4','2','0') ||
133           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ) )
134     {
135         BlendI420( p_filter, p_dst, p_dst_orig, p_src,
136                    i_x_offset, i_y_offset, i_width, i_height );
137         return;
138     }
139     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
140         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
141     {
142         BlendYUY2( p_filter, p_dst, p_dst_orig, p_src,
143                    i_x_offset, i_y_offset, i_width, i_height );
144         return;
145     }
146     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
147         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
148     {
149         BlendR16( p_filter, p_dst, p_dst_orig, p_src,
150                   i_x_offset, i_y_offset, i_width, i_height );
151         return;
152     }
153     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
154         ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','2','4') ||
155           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','3','2') ) )
156     {
157         BlendR24( p_filter, p_dst, p_dst_orig, p_src,
158                   i_x_offset, i_y_offset, i_width, i_height );
159         return;
160     }
161     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','P') &&
162         ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('I','4','2','0') ||
163           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ) )
164     {
165         BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
166                       i_x_offset, i_y_offset, i_width, i_height );
167         return;
168     }
169     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','P') &&
170         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
171     {
172         BlendPalYUY2( p_filter, p_dst, p_dst_orig, p_src,
173                       i_x_offset, i_y_offset, i_width, i_height );
174         return;
175     }
176     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','P') &&
177         ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') ||
178           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','2','4') ||
179           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','3','2') ) )
180     {
181         BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
182                     i_x_offset, i_y_offset, i_width, i_height );
183         return;
184     }
185
186     msg_Dbg( p_filter, "no matching alpha blending routine" );
187 }
188
189 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
190                        picture_t *p_dst_orig, picture_t *p_src,
191                        int i_x_offset, int i_y_offset,
192                        int i_width, int i_height )
193 {
194     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
195     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
196     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
197     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
198     uint8_t *p_trans;
199     int i_x, i_y;
200     vlc_bool_t b_even_scanline = i_y_offset % 2;
201
202     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
203     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
204               p_filter->fmt_out.video.i_x_offset +
205               p_dst->p[Y_PLANE].i_pitch *
206               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
207     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
208               p_filter->fmt_out.video.i_x_offset/2 +
209               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
210               p_dst->p[U_PLANE].i_pitch;
211     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
212               p_filter->fmt_out.video.i_x_offset/2 +
213               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
214               p_dst->p[V_PLANE].i_pitch;
215
216     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
217     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
218                p_filter->fmt_out.video.i_x_offset +
219                p_dst_orig->p[Y_PLANE].i_pitch *
220                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
221     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
222                p_filter->fmt_out.video.i_x_offset/2 +
223                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
224                p_dst_orig->p[U_PLANE].i_pitch;
225     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
226                p_filter->fmt_out.video.i_x_offset/2 +
227                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
228                p_dst_orig->p[V_PLANE].i_pitch;
229
230     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
231     p_src2_y = p_src->p[Y_PLANE].p_pixels +
232                p_filter->fmt_in.video.i_x_offset +
233                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
234     p_src2_u = p_src->p[U_PLANE].p_pixels +
235                p_filter->fmt_in.video.i_x_offset/2 +
236                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
237     p_src2_v = p_src->p[V_PLANE].p_pixels +
238                p_filter->fmt_in.video.i_x_offset/2 +
239                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
240
241     p_trans = p_src->p[A_PLANE].p_pixels +
242               p_filter->fmt_in.video.i_x_offset +
243               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
244
245 #define MAX_TRANS 255
246 #define TRANS_BITS  8
247
248     /* Draw until we reach the bottom of the subtitle */
249     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
250          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
251          p_src2_y += i_src2_pitch,
252          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
253          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
254          p_src2_u += i_src2_pitch,
255          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
256          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
257          p_src2_v += i_src2_pitch )
258     {
259         b_even_scanline = !b_even_scanline;
260
261         /* Draw until we reach the end of the line */
262         for( i_x = 0; i_x < i_width; i_x++ )
263         {
264             if( !p_trans[i_x] )
265             {
266                 /* Completely transparent. Don't change pixel */
267                 continue;
268             }
269             else if( p_trans[i_x] == MAX_TRANS )
270             {
271                 /* Completely opaque. Completely overwrite underlying pixel */
272                 p_dst_y[i_x] = p_src2_y[i_x];
273
274                 if( b_even_scanline && i_x % 2 == 0 )
275                 {
276                     p_dst_u[i_x/2] = p_src2_u[i_x];
277                     p_dst_v[i_x/2] = p_src2_v[i_x];
278                 }
279                 continue;
280             }
281
282             /* Blending */
283             p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * p_trans[i_x] +
284                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - p_trans[i_x]) )
285                 >> TRANS_BITS;
286
287             if( b_even_scanline && i_x % 2 == 0 )
288             {
289                 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * p_trans[i_x] +
290                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - p_trans[i_x]) )
291                 >> TRANS_BITS;
292                 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * p_trans[i_x] +
293                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - p_trans[i_x]) )
294                 >> TRANS_BITS;
295             }
296         }
297     }
298
299 #undef MAX_TRANS
300 #undef TRANS_BITS
301
302     return;
303 }
304
305 static inline void yuv_to_rgb( int *r, int *g, int *b,
306                                uint8_t y1, uint8_t u1, uint8_t v1 )
307 {
308     /* macros used for YUV pixel conversions */
309 #   define SCALEBITS 10
310 #   define ONE_HALF  (1 << (SCALEBITS - 1))
311 #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
312 #   define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
313
314     int y, cb, cr, r_add, g_add, b_add;
315
316     cb = u1 - 128;
317     cr = v1 - 128;
318     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
319     g_add = - FIX(0.34414*255.0/224.0) * cb
320             - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
321     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
322     y = (y1 - 16) * FIX(255.0/219.0);
323     *r = CLAMP((y + r_add) >> SCALEBITS);
324     *g = CLAMP((y + g_add) >> SCALEBITS);
325     *b = CLAMP((y + b_add) >> SCALEBITS);
326 }
327
328 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
329                       picture_t *p_dst_orig, picture_t *p_src,
330                       int i_x_offset, int i_y_offset,
331                       int i_width, int i_height )
332 {
333     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
334     uint8_t *p_dst, *p_src1, *p_src2_y;
335     uint8_t *p_src2_u, *p_src2_v;
336     uint8_t *p_trans;
337     int i_x, i_y, i_pix_pitch;
338     int r, g, b;
339
340     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
341     i_dst_pitch = p_dst_pic->p->i_pitch;
342     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
343             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
344             p_dst_pic->p->i_pitch *
345             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
346
347     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
348     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
349                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
350                p_dst_orig->p->i_pitch *
351                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
352
353     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
354     p_src2_y = p_src->p[Y_PLANE].p_pixels +
355                p_filter->fmt_in.video.i_x_offset +
356                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
357     p_src2_u = p_src->p[U_PLANE].p_pixels +
358                p_filter->fmt_in.video.i_x_offset/2 +
359                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
360     p_src2_v = p_src->p[V_PLANE].p_pixels +
361                p_filter->fmt_in.video.i_x_offset/2 +
362                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
363
364     p_trans = p_src->p[A_PLANE].p_pixels +
365               p_filter->fmt_in.video.i_x_offset +
366               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
367
368 #define MAX_TRANS 255
369 #define TRANS_BITS  8
370
371     /* Draw until we reach the bottom of the subtitle */
372     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
373          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
374          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
375          p_src2_v += i_src2_pitch )
376     {
377         /* Draw until we reach the end of the line */
378         for( i_x = 0; i_x < i_width; i_x++ )
379         {
380             if( !p_trans[i_x] )
381             {
382                 /* Completely transparent. Don't change pixel */
383                 continue;
384             }
385             else if( p_trans[i_x] == MAX_TRANS )
386             {
387                 /* Completely opaque. Completely overwrite underlying pixel */
388                 yuv_to_rgb( &r, &g, &b,
389                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
390
391     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
392                 continue;
393             }
394
395             /* Blending */
396             yuv_to_rgb( &r, &g, &b,
397                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
398
399     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
400         }
401     }
402
403 #undef MAX_TRANS
404 #undef TRANS_BITS
405
406     return;
407 }
408
409 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
410                       picture_t *p_dst_orig, picture_t *p_src,
411                       int i_x_offset, int i_y_offset,
412                       int i_width, int i_height )
413 {
414     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
415     uint8_t *p_dst, *p_src1, *p_src2_y;
416     uint8_t *p_src2_u, *p_src2_v;
417     uint8_t *p_trans;
418     int i_x, i_y, i_pix_pitch;
419     int r, g, b;
420
421     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
422     i_dst_pitch = p_dst_pic->p->i_pitch;
423     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
424             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
425             p_dst_pic->p->i_pitch *
426             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
427
428     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
429     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
430                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
431                p_dst_orig->p->i_pitch *
432                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
433
434     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
435     p_src2_y = p_src->p[Y_PLANE].p_pixels +
436                p_filter->fmt_in.video.i_x_offset +
437                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
438     p_src2_u = p_src->p[U_PLANE].p_pixels +
439                p_filter->fmt_in.video.i_x_offset/2 +
440                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
441     p_src2_v = p_src->p[V_PLANE].p_pixels +
442                p_filter->fmt_in.video.i_x_offset/2 +
443                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
444
445     p_trans = p_src->p[A_PLANE].p_pixels +
446               p_filter->fmt_in.video.i_x_offset +
447               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
448
449 #define MAX_TRANS 255
450 #define TRANS_BITS  8
451
452     /* Draw until we reach the bottom of the subtitle */
453     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
454          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
455          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
456          p_src2_v += i_src2_pitch )
457     {
458         /* Draw until we reach the end of the line */
459         for( i_x = 0; i_x < i_width; i_x++ )
460         {
461             if( !p_trans[i_x] )
462             {
463                 /* Completely transparent. Don't change pixel */
464                 continue;
465             }
466             else if( p_trans[i_x] == MAX_TRANS )
467             {
468                 /* Completely opaque. Completely overwrite underlying pixel */
469                 yuv_to_rgb( &r, &g, &b,
470                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
471
472                 p_dst[i_x * i_pix_pitch]     = r;
473                 p_dst[i_x * i_pix_pitch + 1] = g;
474                 p_dst[i_x * i_pix_pitch + 2] = b;
475                 continue;
476             }
477
478             /* Blending */
479             yuv_to_rgb( &r, &g, &b,
480                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
481
482             p_dst[i_x * i_pix_pitch]     = ( r * p_trans[i_x] +
483                 (uint16_t)p_src1[i_x * i_pix_pitch] *
484                 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
485             p_dst[i_x * i_pix_pitch + 1] = ( g * p_trans[i_x] +
486                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
487                 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
488             p_dst[i_x * i_pix_pitch + 2] = ( b * p_trans[i_x] +
489                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
490                 (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
491         }
492     }
493
494 #undef MAX_TRANS
495 #undef TRANS_BITS
496
497     return;
498 }
499
500 static void BlendYUY2( filter_t *p_filter, picture_t *p_dst_pic,
501                        picture_t *p_dst_orig, picture_t *p_src,
502                        int i_x_offset, int i_y_offset,
503                        int i_width, int i_height )
504 {
505     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
506     uint8_t *p_dst, *p_src1, *p_src2_y;
507     uint8_t *p_src2_u, *p_src2_v;
508     uint8_t *p_trans;
509     int i_x, i_y, i_pix_pitch;
510
511     i_pix_pitch = 2;
512     i_dst_pitch = p_dst_pic->p->i_pitch;
513     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
514             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
515             p_dst_pic->p->i_pitch *
516             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
517
518     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
519     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
520                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
521                p_dst_orig->p->i_pitch *
522                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
523
524     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
525     p_src2_y = p_src->p[Y_PLANE].p_pixels +
526                p_filter->fmt_in.video.i_x_offset +
527                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
528     p_src2_u = p_src->p[U_PLANE].p_pixels +
529                p_filter->fmt_in.video.i_x_offset/2 +
530                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
531     p_src2_v = p_src->p[V_PLANE].p_pixels +
532                p_filter->fmt_in.video.i_x_offset/2 +
533                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
534
535     p_trans = p_src->p[A_PLANE].p_pixels +
536               p_filter->fmt_in.video.i_x_offset +
537               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
538
539 #define MAX_TRANS 255
540 #define TRANS_BITS  8
541
542     /* Draw until we reach the bottom of the subtitle */
543     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
544          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
545          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
546          p_src2_v += i_src2_pitch )
547     {
548         /* Draw until we reach the end of the line */
549         for( i_x = 0; i_x < i_width; i_x += 2 )
550         {
551             if( !p_trans[i_x] )
552             {
553                 /* Completely transparent. Don't change pixel */
554             }
555             else if( p_trans[i_x] == MAX_TRANS )
556             {
557                 /* Completely opaque. Completely overwrite underlying pixel */
558                 p_dst[i_x * 2]     = p_src2_y[i_x];
559                 p_dst[i_x * 2 + 1] = p_src2_u[i_x];
560                 p_dst[i_x * 2 + 3] = p_src2_v[i_x];
561             }
562             else
563             {
564                 /* Blending */
565                 p_dst[i_x * 2]     = ( (uint16_t)p_src2_y[i_x] * p_trans[i_x] +
566                     (uint16_t)p_src1[i_x * 2] *
567                     (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
568                 p_dst[i_x * 2 + 1] = ( (uint16_t)p_src2_u[i_x] * p_trans[i_x] +
569                     (uint16_t)p_src1[i_x * 2 + 1] *
570                     (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
571                 p_dst[i_x * 2 + 3] = ( (uint16_t)p_src2_v[i_x] * p_trans[i_x] +
572                     (uint16_t)p_src1[i_x * 2 + 3] *
573                     (MAX_TRANS - p_trans[i_x]) ) >> TRANS_BITS;
574             }
575
576             if( !p_trans[i_x+1] )
577             {
578                 /* Completely transparent. Don't change pixel */
579             }
580             else if( p_trans[i_x+1] == MAX_TRANS )
581             {
582                 /* Completely opaque. Completely overwrite underlying pixel */
583                 p_dst[i_x * 2 + 2] = p_src2_y[i_x + 1];
584             }
585             else
586             {
587                 /* Blending */
588                 p_dst[i_x * 2 + 2] = ( (uint16_t)p_src2_y[i_x+1] *
589                     p_trans[i_x+1] + (uint16_t)p_src1[i_x * 2 + 2] *
590                     (MAX_TRANS - p_trans[i_x+1]) ) >> TRANS_BITS;
591             }
592         }
593     }
594
595 #undef MAX_TRANS
596 #undef TRANS_BITS
597
598     return;
599 }
600
601 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
602                           picture_t *p_dst_orig, picture_t *p_src,
603                           int i_x_offset, int i_y_offset,
604                           int i_width, int i_height )
605 {
606     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
607     uint8_t *p_src1_y, *p_src2, *p_dst_y;
608     uint8_t *p_src1_u, *p_dst_u;
609     uint8_t *p_src1_v, *p_dst_v;
610     int i_x, i_y;
611     vlc_bool_t b_even_scanline = i_y_offset % 2;
612
613     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
614     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
615               p_filter->fmt_out.video.i_x_offset +
616               p_dst->p[Y_PLANE].i_pitch *
617               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
618     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
619               p_filter->fmt_out.video.i_x_offset/2 +
620               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
621               p_dst->p[U_PLANE].i_pitch;
622     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
623               p_filter->fmt_out.video.i_x_offset/2 +
624               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
625               p_dst->p[V_PLANE].i_pitch;
626
627     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
628     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
629                p_filter->fmt_out.video.i_x_offset +
630                p_dst_orig->p[Y_PLANE].i_pitch *
631                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
632     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
633                p_filter->fmt_out.video.i_x_offset/2 +
634                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
635                p_dst_orig->p[U_PLANE].i_pitch;
636     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
637                p_filter->fmt_out.video.i_x_offset/2 +
638                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
639                p_dst_orig->p[V_PLANE].i_pitch;
640
641     i_src2_pitch = p_src->p->i_pitch;
642     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
643              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
644
645 #define MAX_TRANS 255
646 #define TRANS_BITS  8
647 #define p_trans p_src2
648 #define p_pal p_filter->fmt_in.video.p_palette->palette
649
650     /* Draw until we reach the bottom of the subtitle */
651     for( i_y = 0; i_y < i_height; i_y++,
652          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
653          p_src2 += i_src2_pitch,
654          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
655          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
656          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
657          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
658     {
659         b_even_scanline = !b_even_scanline;
660
661         /* Draw until we reach the end of the line */
662         for( i_x = 0; i_x < i_width; i_x++ )
663         {
664             if( !p_pal[p_trans[i_x]][3] )
665             {
666                 /* Completely transparent. Don't change pixel */
667                 continue;
668             }
669             else if( p_pal[p_trans[i_x]][3] == MAX_TRANS )
670             {
671                 /* Completely opaque. Completely overwrite underlying pixel */
672                 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
673
674                 if( b_even_scanline && i_x % 2 == 0 )
675                 {
676                     p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
677                     p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
678                 }
679                 continue;
680             }
681
682             /* Blending */
683             p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] *
684                 p_pal[p_trans[i_x]][3] + (uint16_t)p_src1_y[i_x] *
685                 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
686
687             if( b_even_scanline && i_x % 2 == 0 )
688             {
689                 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] *
690                     p_pal[p_trans[i_x]][3] + (uint16_t)p_src1_u[i_x/2] *
691                     (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
692                 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] *
693                     p_pal[p_trans[i_x]][3] + (uint16_t)p_src1_v[i_x/2] *
694                     (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
695             }
696         }
697     }
698
699 #undef MAX_TRANS
700 #undef TRANS_BITS
701 #undef p_trans
702 #undef p_pal
703
704     return;
705 }
706
707 static void BlendPalYUY2( filter_t *p_filter, picture_t *p_dst_pic,
708                           picture_t *p_dst_orig, picture_t *p_src,
709                           int i_x_offset, int i_y_offset,
710                           int i_width, int i_height )
711 {
712     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
713     uint8_t *p_src1, *p_src2, *p_dst;
714     int i_x, i_y, i_pix_pitch;
715
716     i_pix_pitch = 2;
717     i_dst_pitch = p_dst_pic->p->i_pitch;
718     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
719             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
720             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
721
722     i_src1_pitch = p_dst_orig->p->i_pitch;
723     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
724              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
725              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
726
727     i_src2_pitch = p_src->p->i_pitch;
728     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
729              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
730
731 #define MAX_TRANS 255
732 #define TRANS_BITS  8
733 #define p_trans p_src2
734 #define p_pal p_filter->fmt_in.video.p_palette->palette
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 += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
739     {
740         /* Draw until we reach the end of the line */
741         for( i_x = 0; i_x < i_width; i_x += 2 )
742         {
743             if( !p_pal[p_trans[i_x]][3] )
744             {
745                 /* Completely transparent. Don't change pixel */
746             }
747             else if( p_pal[p_trans[i_x]][3] == MAX_TRANS )
748             {
749                 /* Completely opaque. Completely overwrite underlying pixel */
750                 p_dst[i_x * 2]     = p_pal[p_src2[i_x]][0];
751                 p_dst[i_x * 2 + 1] = p_pal[p_src2[i_x]][1];
752                 p_dst[i_x * 2 + 3] = p_pal[p_src2[i_x]][2];
753             }
754             else
755             {
756                 /* Blending */
757                 p_dst[i_x * 2]     = ( (uint16_t)p_pal[p_src2[i_x]][0] *
758                     p_pal[p_trans[i_x]][3] + (uint16_t)p_src1[i_x * 2] *
759                     (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
760                 p_dst[i_x * 2 + 1] = ( (uint16_t)p_pal[p_src2[i_x]][1] *
761                     p_pal[p_trans[i_x]][3] + (uint16_t)p_src1[i_x * 2 + 1] *
762                     (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
763                 p_dst[i_x * 2 + 3] = ( (uint16_t)p_pal[p_src2[i_x]][2] *
764                     p_pal[p_trans[i_x]][3] + (uint16_t)p_src1[i_x * 2 + 3] *
765                     (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
766             }
767
768             if( !p_pal[p_trans[i_x+1]][3] )
769             {
770                 /* Completely transparent. Don't change pixel */
771             }
772             else if( p_pal[p_trans[i_x+1]][3] == MAX_TRANS )
773             {
774                 /* Completely opaque. Completely overwrite underlying pixel */
775                 p_dst[i_x * 2 + 2] = p_pal[p_src2[i_x + 1]][0];
776             }
777             else
778             {
779                 /* Blending */
780                 p_dst[i_x * 2 + 2] = ( (uint16_t)p_pal[p_src2[i_x+1]][0] *
781                     p_pal[p_trans[i_x+1]][3] + (uint16_t)p_src1[i_x * 2 + 2] *
782                     (MAX_TRANS - p_pal[p_trans[i_x+1]][3]) ) >> TRANS_BITS;
783             }
784         }
785     }
786
787 #undef MAX_TRANS
788 #undef TRANS_BITS
789 #undef p_trans
790 #undef p_pal
791
792     return;
793 }
794
795 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
796                         picture_t *p_dst_orig, picture_t *p_src,
797                         int i_x_offset, int i_y_offset,
798                         int i_width, int i_height )
799 {
800     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
801     uint8_t *p_src1, *p_src2, *p_dst;
802     int i_x, i_y, i_pix_pitch;
803     int r, g, b;
804     video_palette_t rgbpalette;
805
806     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
807     i_dst_pitch = p_dst_pic->p->i_pitch;
808     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
809             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
810             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
811
812     i_src1_pitch = p_dst_orig->p->i_pitch;
813     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
814              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
815              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
816
817     i_src2_pitch = p_src->p->i_pitch;
818     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
819              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
820
821 #define MAX_TRANS 255
822 #define TRANS_BITS  8
823 #define p_trans p_src2
824 #define p_pal p_filter->fmt_in.video.p_palette->palette
825 #define rgbpal rgbpalette.palette
826
827     /* Convert palette first */
828     for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
829          i_y < 256; i_y++ )
830     {
831         yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
832
833         if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
834         {
835             *(uint16_t *)rgbpal[i_y] =
836                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
837         }
838         else
839         {
840             rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
841         }
842     }
843
844     /* Draw until we reach the bottom of the subtitle */
845     for( i_y = 0; i_y < i_height; i_y++,
846          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
847     {
848         /* Draw until we reach the end of the line */
849         for( i_x = 0; i_x < i_width; i_x++ )
850         {
851             if( !p_pal[p_trans[i_x]][3] )
852             {
853                 /* Completely transparent. Don't change pixel */
854                 continue;
855             }
856             else if( p_pal[p_trans[i_x]][3] == MAX_TRANS ||
857                      p_filter->fmt_out.video.i_chroma ==
858                      VLC_FOURCC('R','V','1','6') )
859             {
860                 /* Completely opaque. Completely overwrite underlying pixel */
861                 p_dst[i_x * i_pix_pitch]     = rgbpal[p_src2[i_x]][0];
862                 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
863                 if( p_filter->fmt_out.video.i_chroma !=
864                     VLC_FOURCC('R','V','1','6') )
865                 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
866                 continue;
867             }
868
869             /* Blending */
870             p_dst[i_x * i_pix_pitch]     = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
871                 p_pal[p_trans[i_x]][3] +
872                 (uint16_t)p_src1[i_x * i_pix_pitch] *
873                 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
874             p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
875                 p_pal[p_trans[i_x]][3] +
876                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
877                 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
878             p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
879                 p_pal[p_trans[i_x]][3] +
880                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
881                 (MAX_TRANS - p_pal[p_trans[i_x]][3]) ) >> TRANS_BITS;
882         }
883     }
884
885 #undef MAX_TRANS
886 #undef TRANS_BITS
887 #undef p_trans
888 #undef p_pal
889 #undef rgbpal
890
891     return;
892 }
893
894 /*****************************************************************************
895  * CloseFilter: clean up the filter
896  *****************************************************************************/
897 static void CloseFilter( vlc_object_t *p_this )
898 {
899     filter_t *p_filter = (filter_t*)p_this;
900     filter_sys_t *p_sys = p_filter->p_sys;
901
902     free( p_sys );
903 }