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