Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

blend.c

00001 /*****************************************************************************
00002  * blend.c: alpha blend 2 pictures together
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: blend.c 12821 2005-10-11 17:16:13Z zorglub $
00006  *
00007  * Author: Gildas Bazin <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <vlc/vlc.h>
00028 #include <vlc/decoder.h>
00029 #include "vlc_filter.h"
00030 
00031 /*****************************************************************************
00032  * filter_sys_t : filter descriptor
00033  *****************************************************************************/
00034 struct filter_sys_t
00035 {
00036     int i_dummy;
00037 };
00038 
00039 /****************************************************************************
00040  * Local prototypes
00041  ****************************************************************************/
00042 static int  OpenFilter ( vlc_object_t * );
00043 static void CloseFilter( vlc_object_t * );
00044 
00045 /* TODO i_alpha support for BlendR16 */
00046 static void Blend( filter_t *, picture_t *, picture_t *, picture_t *,
00047                    int, int, int );
00048 static void BlendI420( filter_t *, picture_t *, picture_t *, picture_t *,
00049                        int, int, int, int, int );
00050 static void BlendR16( filter_t *, picture_t *, picture_t *, picture_t *,
00051                       int, int, int, int, int );
00052 static void BlendR24( filter_t *, picture_t *, picture_t *, picture_t *,
00053                       int, int, int, int, int );
00054 static void BlendYUY2( filter_t *, picture_t *, picture_t *, picture_t *,
00055                        int, int, int, int, int );
00056 static void BlendPalI420( filter_t *, picture_t *, picture_t *, picture_t *,
00057                           int, int, int, int, int );
00058 static void BlendPalYUY2( filter_t *, picture_t *, picture_t *, picture_t *,
00059                           int, int, int, int, int );
00060 static void BlendPalRV( filter_t *, picture_t *, picture_t *, picture_t *,
00061                         int, int, int, int, int );
00062 
00063 /*****************************************************************************
00064  * Module descriptor
00065  *****************************************************************************/
00066 vlc_module_begin();
00067     set_description( _("Video pictures blending") );
00068     set_capability( "video blending", 100 );
00069     set_callbacks( OpenFilter, CloseFilter );
00070 vlc_module_end();
00071 
00072 /*****************************************************************************
00073  * OpenFilter: probe the filter and return score
00074  *****************************************************************************/
00075 static int OpenFilter( vlc_object_t *p_this )
00076 {
00077     filter_t *p_filter = (filter_t*)p_this;
00078     filter_sys_t *p_sys;
00079 
00080     /* Check if we can handle that format.
00081      * We could try to use a chroma filter if we can't. */
00082     if( ( p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','U','V','A') &&
00083           p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','U','V','P') ) ||
00084         ( p_filter->fmt_out.video.i_chroma != VLC_FOURCC('I','4','2','0') &&
00085           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('Y','U','Y','2') &&
00086           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('Y','V','1','2') &&
00087           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','1','6') &&
00088           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','2','4') &&
00089           p_filter->fmt_out.video.i_chroma != VLC_FOURCC('R','V','3','2') ) )
00090     {
00091         return VLC_EGENERIC;
00092     }
00093 
00094     /* Allocate the memory needed to store the decoder's structure */
00095     if( ( p_filter->p_sys = p_sys =
00096           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
00097     {
00098         msg_Err( p_filter, "out of memory" );
00099         return VLC_EGENERIC;
00100     }
00101 
00102     /* Misc init */
00103     p_filter->pf_video_blend = Blend;
00104 
00105     msg_Dbg( p_filter, "chroma: %4.4s -> %4.4s",
00106              (char *)&p_filter->fmt_in.video.i_chroma,
00107              (char *)&p_filter->fmt_out.video.i_chroma );
00108 
00109 
00110     return VLC_SUCCESS;
00111 }
00112 
00113 /****************************************************************************
00114  * Blend: the whole thing
00115  ****************************************************************************
00116  * This function is called just after the thread is launched.
00117  ****************************************************************************/
00118 static void Blend( filter_t *p_filter, picture_t *p_dst,
00119                    picture_t *p_dst_orig, picture_t *p_src,
00120                    int i_x_offset, int i_y_offset, int i_alpha )
00121 {
00122     int i_width, i_height;
00123 
00124     i_width = __MIN((int)p_filter->fmt_out.video.i_visible_width - i_x_offset,
00125                     (int)p_filter->fmt_in.video.i_visible_width);
00126 
00127     i_height = __MIN((int)p_filter->fmt_out.video.i_visible_height -i_y_offset,
00128                      (int)p_filter->fmt_in.video.i_visible_height);
00129 
00130     if( i_width <= 0 || i_height <= 0 ) return;
00131 
00132     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
00133         ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('I','4','2','0') ||
00134           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ) )
00135     {
00136         BlendI420( p_filter, p_dst, p_dst_orig, p_src,
00137                    i_x_offset, i_y_offset, i_width, i_height, i_alpha );
00138         return;
00139     }
00140     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
00141         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
00142     {
00143         BlendYUY2( p_filter, p_dst, p_dst_orig, p_src,
00144                    i_x_offset, i_y_offset, i_width, i_height, i_alpha );
00145         return;
00146     }
00147     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
00148         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
00149     {
00150         BlendR16( p_filter, p_dst, p_dst_orig, p_src,
00151                   i_x_offset, i_y_offset, i_width, i_height, i_alpha );
00152         return;
00153     }
00154     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','A') &&
00155         ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','2','4') ||
00156           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','3','2') ) )
00157     {
00158         BlendR24( p_filter, p_dst, p_dst_orig, p_src,
00159                   i_x_offset, i_y_offset, i_width, i_height, i_alpha );
00160         return;
00161     }
00162     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','P') &&
00163         ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('I','4','2','0') ||
00164           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ) )
00165     {
00166         BlendPalI420( p_filter, p_dst, p_dst_orig, p_src,
00167                       i_x_offset, i_y_offset, i_width, i_height, i_alpha );
00168         return;
00169     }
00170     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','P') &&
00171         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','Y','2') )
00172     {
00173         BlendPalYUY2( p_filter, p_dst, p_dst_orig, p_src,
00174                       i_x_offset, i_y_offset, i_width, i_height, i_alpha );
00175         return;
00176     }
00177     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','U','V','P') &&
00178         ( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') ||
00179           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','2','4') ||
00180           p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','3','2') ) )
00181     {
00182         BlendPalRV( p_filter, p_dst, p_dst_orig, p_src,
00183                     i_x_offset, i_y_offset, i_width, i_height, i_alpha );
00184         return;
00185     }
00186 
00187     msg_Dbg( p_filter, "no matching alpha blending routine" );
00188 }
00189 
00190 static void BlendI420( filter_t *p_filter, picture_t *p_dst,
00191                        picture_t *p_dst_orig, picture_t *p_src,
00192                        int i_x_offset, int i_y_offset,
00193                        int i_width, int i_height, int i_alpha )
00194 {
00195     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
00196     uint8_t *p_src1_y, *p_src2_y, *p_dst_y;
00197     uint8_t *p_src1_u, *p_src2_u, *p_dst_u;
00198     uint8_t *p_src1_v, *p_src2_v, *p_dst_v;
00199     uint8_t *p_trans;
00200     int i_x, i_y, i_trans;
00201     vlc_bool_t b_even_scanline = i_y_offset % 2;
00202 
00203     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
00204     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
00205               p_filter->fmt_out.video.i_x_offset +
00206               p_dst->p[Y_PLANE].i_pitch *
00207               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00208     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
00209               p_filter->fmt_out.video.i_x_offset/2 +
00210               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
00211               p_dst->p[U_PLANE].i_pitch;
00212     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
00213               p_filter->fmt_out.video.i_x_offset/2 +
00214               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
00215               p_dst->p[V_PLANE].i_pitch;
00216 
00217     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
00218     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
00219                p_filter->fmt_out.video.i_x_offset +
00220                p_dst_orig->p[Y_PLANE].i_pitch *
00221                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00222     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
00223                p_filter->fmt_out.video.i_x_offset/2 +
00224                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
00225                p_dst_orig->p[U_PLANE].i_pitch;
00226     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
00227                p_filter->fmt_out.video.i_x_offset/2 +
00228                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
00229                p_dst_orig->p[V_PLANE].i_pitch;
00230 
00231     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
00232     p_src2_y = p_src->p[Y_PLANE].p_pixels +
00233                p_filter->fmt_in.video.i_x_offset +
00234                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
00235     p_src2_u = p_src->p[U_PLANE].p_pixels +
00236                p_filter->fmt_in.video.i_x_offset/2 +
00237                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
00238     p_src2_v = p_src->p[V_PLANE].p_pixels +
00239                p_filter->fmt_in.video.i_x_offset/2 +
00240                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
00241 
00242     p_trans = p_src->p[A_PLANE].p_pixels +
00243               p_filter->fmt_in.video.i_x_offset +
00244               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
00245 
00246 #define MAX_TRANS 255
00247 #define TRANS_BITS  8
00248 
00249     /* Draw until we reach the bottom of the subtitle */
00250     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
00251          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
00252          p_src2_y += i_src2_pitch,
00253          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
00254          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
00255          p_src2_u += i_src2_pitch,
00256          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
00257          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0,
00258          p_src2_v += i_src2_pitch )
00259     {
00260         b_even_scanline = !b_even_scanline;
00261 
00262         /* Draw until we reach the end of the line */
00263         for( i_x = 0; i_x < i_width; i_x++ )
00264         {
00265             i_trans = ( p_trans[i_x] * i_alpha ) / 255;
00266             if( !i_trans )
00267             {
00268                 /* Completely transparent. Don't change pixel */
00269                 continue;
00270             }
00271             else if( i_trans == MAX_TRANS )
00272             {
00273                 /* Completely opaque. Completely overwrite underlying pixel */
00274                 p_dst_y[i_x] = p_src2_y[i_x];
00275 
00276                 if( b_even_scanline && i_x % 2 == 0 )
00277                 {
00278                     p_dst_u[i_x/2] = p_src2_u[i_x];
00279                     p_dst_v[i_x/2] = p_src2_v[i_x];
00280                 }
00281                 continue;
00282             }
00283 
00284             /* Blending */
00285             p_dst_y[i_x] = ( (uint16_t)p_src2_y[i_x] * i_trans +
00286                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
00287                 >> TRANS_BITS;
00288 
00289             if( b_even_scanline && i_x % 2 == 0 )
00290             {
00291                 p_dst_u[i_x/2] = ( (uint16_t)p_src2_u[i_x] * i_trans +
00292                 (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
00293                 >> TRANS_BITS;
00294                 p_dst_v[i_x/2] = ( (uint16_t)p_src2_v[i_x] * i_trans +
00295                 (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
00296                 >> TRANS_BITS;
00297             }
00298         }
00299     }
00300 
00301 #undef MAX_TRANS
00302 #undef TRANS_BITS
00303 
00304     return;
00305 }
00306 
00307 static inline void yuv_to_rgb( int *r, int *g, int *b,
00308                                uint8_t y1, uint8_t u1, uint8_t v1 )
00309 {
00310     /* macros used for YUV pixel conversions */
00311 #   define SCALEBITS 10
00312 #   define ONE_HALF  (1 << (SCALEBITS - 1))
00313 #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
00314 #   define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
00315 
00316     int y, cb, cr, r_add, g_add, b_add;
00317 
00318     cb = u1 - 128;
00319     cr = v1 - 128;
00320     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
00321     g_add = - FIX(0.34414*255.0/224.0) * cb
00322             - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
00323     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
00324     y = (y1 - 16) * FIX(255.0/219.0);
00325     *r = CLAMP((y + r_add) >> SCALEBITS);
00326     *g = CLAMP((y + g_add) >> SCALEBITS);
00327     *b = CLAMP((y + b_add) >> SCALEBITS);
00328 }
00329 
00330 static void BlendR16( filter_t *p_filter, picture_t *p_dst_pic,
00331                       picture_t *p_dst_orig, picture_t *p_src,
00332                       int i_x_offset, int i_y_offset,
00333                       int i_width, int i_height, int i_alpha )
00334 {
00335     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
00336     uint8_t *p_dst, *p_src1, *p_src2_y;
00337     uint8_t *p_src2_u, *p_src2_v;
00338     uint8_t *p_trans;
00339     int i_x, i_y, i_pix_pitch;
00340     int r, g, b;
00341 
00342     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
00343     i_dst_pitch = p_dst_pic->p->i_pitch;
00344     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
00345             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
00346             p_dst_pic->p->i_pitch *
00347             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00348 
00349     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
00350     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
00351                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
00352                p_dst_orig->p->i_pitch *
00353                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00354 
00355     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
00356     p_src2_y = p_src->p[Y_PLANE].p_pixels +
00357                p_filter->fmt_in.video.i_x_offset +
00358                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
00359     p_src2_u = p_src->p[U_PLANE].p_pixels +
00360                p_filter->fmt_in.video.i_x_offset/2 +
00361                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
00362     p_src2_v = p_src->p[V_PLANE].p_pixels +
00363                p_filter->fmt_in.video.i_x_offset/2 +
00364                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
00365 
00366     p_trans = p_src->p[A_PLANE].p_pixels +
00367               p_filter->fmt_in.video.i_x_offset +
00368               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
00369 
00370 #define MAX_TRANS 255
00371 #define TRANS_BITS  8
00372 
00373     /* Draw until we reach the bottom of the subtitle */
00374     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
00375          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
00376          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
00377          p_src2_v += i_src2_pitch )
00378     {
00379         /* Draw until we reach the end of the line */
00380         for( i_x = 0; i_x < i_width; i_x++ )
00381         {
00382             if( !p_trans[i_x] )
00383             {
00384                 /* Completely transparent. Don't change pixel */
00385                 continue;
00386             }
00387             else if( p_trans[i_x] == MAX_TRANS )
00388             {
00389                 /* Completely opaque. Completely overwrite underlying pixel */
00390                 yuv_to_rgb( &r, &g, &b,
00391                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
00392 
00393     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
00394                 continue;
00395             }
00396 
00397             /* Blending */
00398             yuv_to_rgb( &r, &g, &b,
00399                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
00400 
00401     ((uint16_t *)(&p_dst[i_x * i_pix_pitch]))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
00402         }
00403     }
00404 
00405 #undef MAX_TRANS
00406 #undef TRANS_BITS
00407 
00408     return;
00409 }
00410 
00411 static void BlendR24( filter_t *p_filter, picture_t *p_dst_pic,
00412                       picture_t *p_dst_orig, picture_t *p_src,
00413                       int i_x_offset, int i_y_offset,
00414                       int i_width, int i_height, int i_alpha )
00415 {
00416     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
00417     uint8_t *p_dst, *p_src1, *p_src2_y;
00418     uint8_t *p_src2_u, *p_src2_v;
00419     uint8_t *p_trans;
00420     int i_x, i_y, i_pix_pitch, i_trans;
00421     int r, g, b;
00422 
00423     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
00424     i_dst_pitch = p_dst_pic->p->i_pitch;
00425     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
00426             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
00427             p_dst_pic->p->i_pitch *
00428             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00429 
00430     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
00431     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
00432                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
00433                p_dst_orig->p->i_pitch *
00434                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00435 
00436     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
00437     p_src2_y = p_src->p[Y_PLANE].p_pixels +
00438                p_filter->fmt_in.video.i_x_offset +
00439                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
00440     p_src2_u = p_src->p[U_PLANE].p_pixels +
00441                p_filter->fmt_in.video.i_x_offset/2 +
00442                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
00443     p_src2_v = p_src->p[V_PLANE].p_pixels +
00444                p_filter->fmt_in.video.i_x_offset/2 +
00445                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
00446 
00447     p_trans = p_src->p[A_PLANE].p_pixels +
00448               p_filter->fmt_in.video.i_x_offset +
00449               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
00450 
00451 #define MAX_TRANS 255
00452 #define TRANS_BITS  8
00453 
00454     /* Draw until we reach the bottom of the subtitle */
00455     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
00456          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
00457          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
00458          p_src2_v += i_src2_pitch )
00459     {
00460         /* Draw until we reach the end of the line */
00461         for( i_x = 0; i_x < i_width; i_x++ )
00462         {
00463             i_trans = ( p_trans[i_x] * i_alpha ) / 255;
00464             if( !i_trans )
00465             {
00466                 /* Completely transparent. Don't change pixel */
00467                 continue;
00468             }
00469             else if( i_trans == MAX_TRANS )
00470             {
00471                 /* Completely opaque. Completely overwrite underlying pixel */
00472                 yuv_to_rgb( &r, &g, &b,
00473                             p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
00474 
00475                 p_dst[i_x * i_pix_pitch]     = r;
00476                 p_dst[i_x * i_pix_pitch + 1] = g;
00477                 p_dst[i_x * i_pix_pitch + 2] = b;
00478                 continue;
00479             }
00480 
00481             /* Blending */
00482             yuv_to_rgb( &r, &g, &b,
00483                         p_src2_y[i_x], p_src2_u[i_x], p_src2_v[i_x] );
00484 
00485             p_dst[i_x * i_pix_pitch]     = ( r * i_trans +
00486                 (uint16_t)p_src1[i_x * i_pix_pitch] *
00487                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00488             p_dst[i_x * i_pix_pitch + 1] = ( g * i_trans +
00489                 (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
00490                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00491             p_dst[i_x * i_pix_pitch + 2] = ( b * i_trans +
00492                 (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
00493                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00494         }
00495     }
00496 
00497 #undef MAX_TRANS
00498 #undef TRANS_BITS
00499 
00500     return;
00501 }
00502 
00503 static void BlendYUY2( filter_t *p_filter, picture_t *p_dst_pic,
00504                        picture_t *p_dst_orig, picture_t *p_src,
00505                        int i_x_offset, int i_y_offset,
00506                        int i_width, int i_height, int i_alpha )
00507 {
00508     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
00509     uint8_t *p_dst, *p_src1, *p_src2_y;
00510     uint8_t *p_src2_u, *p_src2_v;
00511     uint8_t *p_trans;
00512     int i_x, i_y, i_pix_pitch, i_trans;
00513     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
00514 
00515     i_pix_pitch = 2;
00516     i_dst_pitch = p_dst_pic->p->i_pitch;
00517     p_dst = p_dst_pic->p->p_pixels + i_x_offset * i_pix_pitch +
00518             p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
00519             p_dst_pic->p->i_pitch *
00520             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00521 
00522     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
00523     p_src1 = p_dst_orig->p->p_pixels + i_x_offset * i_pix_pitch +
00524                p_filter->fmt_out.video.i_x_offset * i_pix_pitch +
00525                p_dst_orig->p->i_pitch *
00526                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00527 
00528     i_src2_pitch = p_src->p[Y_PLANE].i_pitch;
00529     p_src2_y = p_src->p[Y_PLANE].p_pixels +
00530                p_filter->fmt_in.video.i_x_offset +
00531                p_src->p[Y_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
00532     p_src2_u = p_src->p[U_PLANE].p_pixels +
00533                p_filter->fmt_in.video.i_x_offset/2 +
00534                p_src->p[U_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
00535     p_src2_v = p_src->p[V_PLANE].p_pixels +
00536                p_filter->fmt_in.video.i_x_offset/2 +
00537                p_src->p[V_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset/2;
00538 
00539     p_trans = p_src->p[A_PLANE].p_pixels +
00540               p_filter->fmt_in.video.i_x_offset +
00541               p_src->p[A_PLANE].i_pitch * p_filter->fmt_in.video.i_y_offset;
00542 
00543     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
00544 
00545 #define MAX_TRANS 255
00546 #define TRANS_BITS  8
00547 
00548     /* Draw until we reach the bottom of the subtitle */
00549     for( i_y = 0; i_y < i_height; i_y++, p_trans += i_src2_pitch,
00550          p_dst += i_dst_pitch, p_src1 += i_src1_pitch,
00551          p_src2_y += i_src2_pitch, p_src2_u += i_src2_pitch,
00552          p_src2_v += i_src2_pitch )
00553     {
00554         /* Draw until we reach the end of the line */
00555         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
00556         {
00557             i_trans = ( p_trans[i_x] * i_alpha ) / 255;
00558             if( !i_trans )
00559             {
00560                 /* Completely transparent. Don't change pixel */
00561             }
00562             else if( i_trans == MAX_TRANS )
00563             {
00564                 /* Completely opaque. Completely overwrite underlying pixel */
00565                 p_dst[i_x * 2]     = p_src2_y[i_x];
00566 
00567                 if( b_even )
00568                 {
00569                     p_dst[i_x * 2 + 1] = p_src2_u[i_x];
00570                     p_dst[i_x * 2 + 3] = p_src2_v[i_x];
00571                 }
00572             }
00573             else
00574             {
00575                 /* Blending */
00576                 p_dst[i_x * 2]     = ( (uint16_t)p_src2_y[i_x] * i_trans +
00577                     (uint16_t)p_src1[i_x * 2] * (MAX_TRANS - i_trans) )
00578                     >> TRANS_BITS;
00579 
00580                 if( b_even )
00581                 {
00582                     p_dst[i_x * 2 + 1] = ( (uint16_t)p_src2_u[i_x] * i_trans +
00583                         (uint16_t)p_src1[i_x * 2 + 1] * (MAX_TRANS - i_trans) )
00584                         >> TRANS_BITS;
00585                     p_dst[i_x * 2 + 3] = ( (uint16_t)p_src2_v[i_x] * i_trans +
00586                         (uint16_t)p_src1[i_x * 2 + 3] * (MAX_TRANS - i_trans) )
00587                         >> TRANS_BITS;
00588                 }
00589             }
00590         }
00591     }
00592 
00593 #undef MAX_TRANS
00594 #undef TRANS_BITS
00595 
00596     return;
00597 }
00598 
00599 static void BlendPalI420( filter_t *p_filter, picture_t *p_dst,
00600                           picture_t *p_dst_orig, picture_t *p_src,
00601                           int i_x_offset, int i_y_offset,
00602                           int i_width, int i_height, int i_alpha )
00603 {
00604     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
00605     uint8_t *p_src1_y, *p_src2, *p_dst_y;
00606     uint8_t *p_src1_u, *p_dst_u;
00607     uint8_t *p_src1_v, *p_dst_v;
00608     int i_x, i_y, i_trans;
00609     vlc_bool_t b_even_scanline = i_y_offset % 2;
00610 
00611     i_dst_pitch = p_dst->p[Y_PLANE].i_pitch;
00612     p_dst_y = p_dst->p[Y_PLANE].p_pixels + i_x_offset +
00613               p_filter->fmt_out.video.i_x_offset +
00614               p_dst->p[Y_PLANE].i_pitch *
00615               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00616     p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
00617               p_filter->fmt_out.video.i_x_offset/2 +
00618               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
00619               p_dst->p[U_PLANE].i_pitch;
00620     p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
00621               p_filter->fmt_out.video.i_x_offset/2 +
00622               ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
00623               p_dst->p[V_PLANE].i_pitch;
00624 
00625     i_src1_pitch = p_dst_orig->p[Y_PLANE].i_pitch;
00626     p_src1_y = p_dst_orig->p[Y_PLANE].p_pixels + i_x_offset +
00627                p_filter->fmt_out.video.i_x_offset +
00628                p_dst_orig->p[Y_PLANE].i_pitch *
00629                ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00630     p_src1_u = p_dst_orig->p[U_PLANE].p_pixels + i_x_offset/2 +
00631                p_filter->fmt_out.video.i_x_offset/2 +
00632                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
00633                p_dst_orig->p[U_PLANE].i_pitch;
00634     p_src1_v = p_dst_orig->p[V_PLANE].p_pixels + i_x_offset/2 +
00635                p_filter->fmt_out.video.i_x_offset/2 +
00636                ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
00637                p_dst_orig->p[V_PLANE].i_pitch;
00638 
00639     i_src2_pitch = p_src->p->i_pitch;
00640     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
00641              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
00642 
00643 #define MAX_TRANS 255
00644 #define TRANS_BITS  8
00645 #define p_trans p_src2
00646 #define p_pal p_filter->fmt_in.video.p_palette->palette
00647 
00648     /* Draw until we reach the bottom of the subtitle */
00649     for( i_y = 0; i_y < i_height; i_y++,
00650          p_dst_y += i_dst_pitch, p_src1_y += i_src1_pitch,
00651          p_src2 += i_src2_pitch,
00652          p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
00653          p_src1_u += b_even_scanline ? i_src1_pitch/2 : 0,
00654          p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
00655          p_src1_v += b_even_scanline ? i_src1_pitch/2 : 0 )
00656     {
00657         b_even_scanline = !b_even_scanline;
00658 
00659         /* Draw until we reach the end of the line */
00660         for( i_x = 0; i_x < i_width; i_x++ )
00661         {
00662             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
00663             if( !i_trans )
00664             {
00665                 /* Completely transparent. Don't change pixel */
00666                 continue;
00667             }
00668             else if( i_trans == MAX_TRANS )
00669             {
00670                 /* Completely opaque. Completely overwrite underlying pixel */
00671                 p_dst_y[i_x] = p_pal[p_src2[i_x]][0];
00672 
00673                 if( b_even_scanline && i_x % 2 == 0 )
00674                 {
00675                     p_dst_u[i_x/2] = p_pal[p_src2[i_x]][1];
00676                     p_dst_v[i_x/2] = p_pal[p_src2[i_x]][2];
00677                 }
00678                 continue;
00679             }
00680 
00681             /* Blending */
00682             p_dst_y[i_x] = ( (uint16_t)p_pal[p_src2[i_x]][0] * i_trans +
00683                 (uint16_t)p_src1_y[i_x] * (MAX_TRANS - i_trans) )
00684                 >> TRANS_BITS;
00685 
00686             if( b_even_scanline && i_x % 2 == 0 )
00687             {
00688                 p_dst_u[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][1] * i_trans +
00689                     (uint16_t)p_src1_u[i_x/2] * (MAX_TRANS - i_trans) )
00690                     >> TRANS_BITS;
00691                 p_dst_v[i_x/2] = ( (uint16_t)p_pal[p_src2[i_x]][2] * i_trans +
00692                     (uint16_t)p_src1_v[i_x/2] * (MAX_TRANS - i_trans) )
00693                     >> TRANS_BITS;
00694             }
00695         }
00696     }
00697 
00698 #undef MAX_TRANS
00699 #undef TRANS_BITS
00700 #undef p_trans
00701 #undef p_pal
00702 
00703     return;
00704 }
00705 
00706 static void BlendPalYUY2( filter_t *p_filter, picture_t *p_dst_pic,
00707                           picture_t *p_dst_orig, picture_t *p_src,
00708                           int i_x_offset, int i_y_offset,
00709                           int i_width, int i_height, int i_alpha )
00710 {
00711     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
00712     uint8_t *p_src1, *p_src2, *p_dst;
00713     int i_x, i_y, i_pix_pitch, i_trans;
00714     vlc_bool_t b_even = !((i_x_offset + p_filter->fmt_out.video.i_x_offset)%2);
00715 
00716     i_pix_pitch = 2;
00717     i_dst_pitch = p_dst_pic->p->i_pitch;
00718     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
00719             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
00720             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00721 
00722     i_src1_pitch = p_dst_orig->p->i_pitch;
00723     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
00724              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
00725              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00726 
00727     i_src2_pitch = p_src->p->i_pitch;
00728     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
00729              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
00730 
00731     i_width = (i_width >> 1) << 1; /* Needs to be a multiple of 2 */
00732 
00733 #define MAX_TRANS 255
00734 #define TRANS_BITS  8
00735 #define p_trans p_src2
00736 #define p_pal p_filter->fmt_in.video.p_palette->palette
00737 
00738     /* Draw until we reach the bottom of the subtitle */
00739     for( i_y = 0; i_y < i_height; i_y++,
00740          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
00741     {
00742         /* Draw until we reach the end of the line */
00743         for( i_x = 0; i_x < i_width; i_x++, b_even = !b_even )
00744         {
00745             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
00746             if( !i_trans )
00747             {
00748                 /* Completely transparent. Don't change pixel */
00749             }
00750             else if( i_trans == MAX_TRANS )
00751             {
00752                 /* Completely opaque. Completely overwrite underlying pixel */
00753                 p_dst[i_x * 2]     = p_pal[p_src2[i_x]][0];
00754 
00755                 if( b_even )
00756                 {
00757                     p_dst[i_x * 2 + 1] = p_pal[p_src2[i_x]][1];
00758                     p_dst[i_x * 2 + 3] = p_pal[p_src2[i_x]][2];
00759                 }
00760             }
00761             else
00762             {
00763                 /* Blending */
00764                 p_dst[i_x * 2]     = ( (uint16_t)p_pal[p_src2[i_x]][0] *
00765                     i_trans + (uint16_t)p_src1[i_x * 2] *
00766                     (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00767 
00768                 if( b_even )
00769                 {
00770                     p_dst[i_x * 2 + 1] = ( (uint16_t)p_pal[p_src2[i_x]][1] *
00771                         i_trans + (uint16_t)p_src1[i_x * 2 + 1] *
00772                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00773                     p_dst[i_x * 2 + 3] = ( (uint16_t)p_pal[p_src2[i_x]][2] *
00774                         i_trans + (uint16_t)p_src1[i_x * 2 + 3] *
00775                         (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00776                 }
00777             }
00778         }
00779     }
00780 
00781 #undef MAX_TRANS
00782 #undef TRANS_BITS
00783 #undef p_trans
00784 #undef p_pal
00785 
00786     return;
00787 }
00788 
00789 static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
00790                         picture_t *p_dst_orig, picture_t *p_src,
00791                         int i_x_offset, int i_y_offset,
00792                         int i_width, int i_height, int i_alpha )
00793 {
00794     int i_src1_pitch, i_src2_pitch, i_dst_pitch;
00795     uint8_t *p_src1, *p_src2, *p_dst;
00796     int i_x, i_y, i_pix_pitch, i_trans;
00797     int r, g, b;
00798     video_palette_t rgbpalette;
00799 
00800     i_pix_pitch = p_dst_pic->p->i_pixel_pitch;
00801     i_dst_pitch = p_dst_pic->p->i_pitch;
00802     p_dst = p_dst_pic->p->p_pixels + i_pix_pitch * (i_x_offset +
00803             p_filter->fmt_out.video.i_x_offset) + p_dst_pic->p->i_pitch *
00804             ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00805 
00806     i_src1_pitch = p_dst_orig->p->i_pitch;
00807     p_src1 = p_dst_orig->p->p_pixels + i_pix_pitch * (i_x_offset +
00808              p_filter->fmt_out.video.i_x_offset) + p_dst_orig->p->i_pitch *
00809              ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
00810 
00811     i_src2_pitch = p_src->p->i_pitch;
00812     p_src2 = p_src->p->p_pixels + p_filter->fmt_in.video.i_x_offset +
00813              i_src2_pitch * p_filter->fmt_in.video.i_y_offset;
00814 
00815 #define MAX_TRANS 255
00816 #define TRANS_BITS  8
00817 #define p_trans p_src2
00818 #define p_pal p_filter->fmt_in.video.p_palette->palette
00819 #define rgbpal rgbpalette.palette
00820 
00821     /* Convert palette first */
00822     for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
00823          i_y < 256; i_y++ )
00824     {
00825         yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
00826 
00827         if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('R','V','1','6') )
00828         {
00829             *(uint16_t *)rgbpal[i_y] =
00830                 ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
00831         }
00832         else
00833         {
00834             rgbpal[i_y][0] = r; rgbpal[i_y][1] = g; rgbpal[i_y][2] = b;
00835         }
00836     }
00837 
00838     /* Draw until we reach the bottom of the subtitle */
00839     for( i_y = 0; i_y < i_height; i_y++,
00840          p_dst += i_dst_pitch, p_src1 += i_src1_pitch, p_src2 += i_src2_pitch )
00841     {
00842         /* Draw until we reach the end of the line */
00843         for( i_x = 0; i_x < i_width; i_x++ )
00844         {
00845             i_trans = ( p_pal[p_trans[i_x]][3] * i_alpha ) / 255;
00846             if( !i_trans )
00847             {
00848                 /* Completely transparent. Don't change pixel */
00849                 continue;
00850             }
00851             else if( i_trans == MAX_TRANS ||
00852                      p_filter->fmt_out.video.i_chroma ==
00853                      VLC_FOURCC('R','V','1','6') )
00854             {
00855                 /* Completely opaque. Completely overwrite underlying pixel */
00856                 p_dst[i_x * i_pix_pitch]     = rgbpal[p_src2[i_x]][0];
00857                 p_dst[i_x * i_pix_pitch + 1] = rgbpal[p_src2[i_x]][1];
00858                 if( p_filter->fmt_out.video.i_chroma !=
00859                     VLC_FOURCC('R','V','1','6') )
00860                 p_dst[i_x * i_pix_pitch + 2] = rgbpal[p_src2[i_x]][2];
00861                 continue;
00862             }
00863 
00864             /* Blending */
00865             p_dst[i_x * i_pix_pitch]     = ( (uint16_t)rgbpal[p_src2[i_x]][0] *
00866                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch] *
00867                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00868             p_dst[i_x * i_pix_pitch + 1] = ( (uint16_t)rgbpal[p_src2[i_x]][1] *
00869                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 1] *
00870                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00871             p_dst[i_x * i_pix_pitch + 2] = ( (uint16_t)rgbpal[p_src2[i_x]][2] *
00872                 i_trans + (uint16_t)p_src1[i_x * i_pix_pitch + 2] *
00873                 (MAX_TRANS - i_trans) ) >> TRANS_BITS;
00874         }
00875     }
00876 
00877 #undef MAX_TRANS
00878 #undef TRANS_BITS
00879 #undef p_trans
00880 #undef p_pal
00881 #undef rgbpal
00882 
00883     return;
00884 }
00885 
00886 /*****************************************************************************
00887  * CloseFilter: clean up the filter
00888  *****************************************************************************/
00889 static void CloseFilter( vlc_object_t *p_this )
00890 {
00891     filter_t *p_filter = (filter_t*)p_this;
00892     filter_sys_t *p_sys = p_filter->p_sys;
00893 
00894     free( p_sys );
00895 }

Generated on Tue Dec 20 10:14:51 2005 for vlc-0.8.4a by  doxygen 1.4.2