1 /*****************************************************************************
2 * render.c : SPU renderer
3 *****************************************************************************
4 * Copyright (C) 2000-2001 VideoLAN
5 * $Id: render.c,v 1.3 2002/11/06 18:07:57 sam Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Rudolf Cornelissen <rag.cornelissen@inter.nl.net>
9 * Roine Gustafsson <roine@popstar.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
29 #include <stdlib.h> /* malloc(), free() */
30 #include <string.h> /* memcpy(), memset() */
34 #include <vlc/decoder.h>
37 # include <unistd.h> /* getpid() */
40 #ifdef WIN32 /* getpid() for win32 is located in process.h */
46 /*****************************************************************************
48 *****************************************************************************/
49 static void RenderI420( vout_thread_t *, picture_t *, const subpicture_t *,
51 static void RenderRV16( vout_thread_t *, picture_t *, const subpicture_t *,
53 static void RenderRV32( vout_thread_t *, picture_t *, const subpicture_t *,
55 static void RenderYUY2( vout_thread_t *, picture_t *, const subpicture_t *,
58 /*****************************************************************************
59 * RenderSPU: draw an SPU on a picture
60 *****************************************************************************
61 * This is a fast implementation of the subpicture drawing code. The data
62 * has been preprocessed once, so we don't need to parse the RLE buffer again
63 * and again. Most sanity checks are already done so that this routine can be
64 * as fast as possible.
65 *****************************************************************************/
66 void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
67 const subpicture_t *p_spu )
69 switch( p_vout->output.i_chroma )
71 /* I420 target, no scaling */
72 case VLC_FOURCC('I','4','2','0'):
73 case VLC_FOURCC('I','Y','U','V'):
74 case VLC_FOURCC('Y','V','1','2'):
75 RenderI420( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
78 /* RV16 target, scaling */
79 case VLC_FOURCC('R','V','1','6'):
80 RenderRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
83 /* RV32 target, scaling */
84 case VLC_FOURCC('R','V','2','4'):
85 case VLC_FOURCC('R','V','3','2'):
86 RenderRV32( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
89 /* NVidia overlay, no scaling */
90 case VLC_FOURCC('Y','U','Y','2'):
91 RenderYUY2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
95 msg_Err( p_vout, "unknown chroma, can't render SPU" );
100 /* Following functions are local */
102 static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
103 const subpicture_t *p_spu, vlc_bool_t b_crop )
105 /* Common variables */
108 u16 *p_source = (u16 *)p_spu->p_sys->p_data;
112 u16 i_colprecomp, i_destalpha;
115 int i_x_start, i_y_start, i_x_end, i_y_end;
117 p_dest = p_pic->Y_PIXELS + p_spu->i_x + p_spu->i_width
118 + p_pic->Y_PITCH * ( p_spu->i_y + p_spu->i_height );
120 i_x_start = p_spu->i_width - p_spu->p_sys->i_x_end;
121 i_y_start = p_pic->Y_PITCH * (p_spu->i_height - p_spu->p_sys->i_y_end );
122 i_x_end = p_spu->i_width - p_spu->p_sys->i_x_start;
123 i_y_end = p_pic->Y_PITCH * (p_spu->i_height - p_spu->p_sys->i_y_start );
125 /* Draw until we reach the bottom of the subtitle */
126 for( i_y = p_spu->i_height * p_pic->Y_PITCH ;
128 i_y -= p_pic->Y_PITCH )
130 /* Draw until we reach the end of the line */
131 for( i_x = p_spu->i_width ; i_x ; i_x -= i_len )
133 /* Get the RLE part, then draw the line */
134 i_color = *p_source & 0x3;
135 i_len = *p_source++ >> 2;
138 && ( i_x < i_x_start || i_x > i_x_end
139 || i_y < i_y_start || i_y > i_y_end ) )
144 switch( p_spu->p_sys->pi_alpha[i_color] )
150 memset( p_dest - i_x - i_y,
151 p_spu->p_sys->pi_yuv[i_color][0], i_len );
155 /* To be able to divide by 16 (>>4) we add 1 to the alpha.
156 * This means Alpha 0 won't be completely transparent, but
157 * that's handled in a special case above anyway. */
158 i_colprecomp = (u16)p_spu->p_sys->pi_yuv[i_color][0]
159 * (u16)(p_spu->p_sys->pi_alpha[i_color] + 1);
160 i_destalpha = 15 - p_spu->p_sys->pi_alpha[i_color];
162 for ( p_destptr = p_dest - i_x - i_y;
163 p_destptr < p_dest - i_x - i_y + i_len;
166 *p_destptr = ( i_colprecomp +
167 (u16)*p_destptr * i_destalpha ) >> 4;
175 static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
176 const subpicture_t *p_spu, vlc_bool_t b_crop )
178 /* Common variables */
181 u16 *p_source = (u16 *)p_spu->p_sys->p_data;
187 int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
190 int i_x_start, i_y_start, i_x_end, i_y_end;
192 /* XXX: this is a COMPLETE HACK, memcpy is unable to do u16s anyway */
193 /* FIXME: get this from the DVD */
194 for( i_color = 0; i_color < 4; i_color++ )
196 p_clut16[i_color] = 0x1111
197 * ( (u16)p_spu->p_sys->pi_yuv[i_color][0] >> 4 );
200 i_xscale = ( p_vout->output.i_width << 6 ) / p_vout->render.i_width;
201 i_yscale = ( p_vout->output.i_height << 6 ) / p_vout->render.i_height;
203 i_width = p_spu->i_width * i_xscale;
204 i_height = p_spu->i_height * i_yscale;
206 p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 2
207 /* Add the picture coordinates and the SPU coordinates */
208 + ( (p_spu->i_x * i_xscale) >> 6 ) * 2
209 + ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
211 i_x_start = i_width - i_xscale * p_spu->p_sys->i_x_end;
212 i_y_start = i_yscale * p_spu->p_sys->i_y_start;
213 i_x_end = i_width - i_xscale * p_spu->p_sys->i_x_start;
214 i_y_end = i_yscale * p_spu->p_sys->i_y_end;
216 /* Draw until we reach the bottom of the subtitle */
217 for( i_y = 0 ; i_y < i_height ; )
222 /* Check whether we need to draw one line or more than one */
223 if( i_ytmp + 1 >= ( i_y >> 6 ) )
225 /* Just one line : we precalculate i_y >> 6 */
226 i_yreal = p_pic->p->i_pitch * i_ytmp;
228 /* Draw until we reach the end of the line */
229 for( i_x = i_width ; i_x ; i_x -= i_len )
231 /* Get the RLE part, then draw the line */
232 i_color = *p_source & 0x3;
233 i_len = i_xscale * ( *p_source++ >> 2 );
236 && ( i_x < i_x_start || i_x > i_x_end
237 || i_y < i_y_start || i_y > i_y_end ) )
242 switch( p_spu->p_sys->pi_alpha[ i_color ] )
248 memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
250 2 * ( ( i_len >> 6 ) + 1 ) );
254 /* FIXME: we should do transparency */
255 memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
257 2 * ( ( i_len >> 6 ) + 1 ) );
264 i_yreal = p_pic->p->i_pitch * i_ytmp;
265 i_ynext = p_pic->p->i_pitch * i_y >> 6;
267 /* Draw until we reach the end of the line */
268 for( i_x = i_width ; i_x ; i_x -= i_len )
270 /* Get the RLE part, then draw as many lines as needed */
271 i_color = *p_source & 0x3;
272 i_len = i_xscale * ( *p_source++ >> 2 );
275 && ( i_x < i_x_start || i_x > i_x_end
276 || i_y < i_y_start || i_y > i_y_end ) )
281 switch( p_spu->p_sys->pi_alpha[ i_color ] )
287 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
288 i_ytmp += p_pic->p->i_pitch )
290 memset( p_dest - 2 * ( i_x >> 6 ) + i_ytmp,
292 2 * ( ( i_len >> 6 ) + 1 ) );
297 /* FIXME: we should do transparency */
298 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
299 i_ytmp += p_pic->p->i_pitch )
301 memset( p_dest - 2 * ( i_x >> 6 ) + i_ytmp,
303 2 * ( ( i_len >> 6 ) + 1 ) );
312 static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
313 const subpicture_t *p_spu, vlc_bool_t b_crop )
315 /* Common variables */
318 u16 *p_source = (u16 *)p_spu->p_sys->p_data;
324 int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
327 int i_x_start, i_y_start, i_x_end, i_y_end;
329 /* XXX: this is a COMPLETE HACK, memcpy is unable to do u32s anyway */
330 /* FIXME: get this from the DVD */
331 for( i_color = 0; i_color < 4; i_color++ )
333 p_clut32[i_color] = 0x11111111
334 * ( (u16)p_spu->p_sys->pi_yuv[i_color][0] >> 4 );
337 i_xscale = ( p_vout->output.i_width << 6 ) / p_vout->render.i_width;
338 i_yscale = ( p_vout->output.i_height << 6 ) / p_vout->render.i_height;
340 i_width = p_spu->i_width * i_xscale;
341 i_height = p_spu->i_height * i_yscale;
343 i_x_start = i_width - i_xscale * p_spu->p_sys->i_x_end;
344 i_y_start = i_yscale * p_spu->p_sys->i_y_start;
345 i_x_end = i_width - i_xscale * p_spu->p_sys->i_x_start;
346 i_y_end = i_yscale * p_spu->p_sys->i_y_end;
348 p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 4
349 /* Add the picture coordinates and the SPU coordinates */
350 + ( (p_spu->i_x * i_xscale) >> 6 ) * 4
351 + ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
353 /* Draw until we reach the bottom of the subtitle */
354 for( i_y = 0 ; i_y < i_height ; )
359 /* Check whether we need to draw one line or more than one */
360 if( i_ytmp + 1 >= ( i_y >> 6 ) )
362 /* Just one line : we precalculate i_y >> 6 */
363 i_yreal = p_pic->p->i_pitch * i_ytmp;
365 /* Draw until we reach the end of the line */
366 for( i_x = i_width ; i_x ; i_x -= i_len )
368 /* Get the RLE part, then draw the line */
369 i_color = *p_source & 0x3;
370 i_len = i_xscale * ( *p_source++ >> 2 );
373 && ( i_x < i_x_start || i_x > i_x_end
374 || i_y < i_y_start || i_y > i_y_end ) )
379 switch( p_spu->p_sys->pi_alpha[ i_color ] )
385 memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal,
386 p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) );
390 /* FIXME: we should do transparency */
391 memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal,
392 p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) );
399 i_yreal = p_pic->p->i_pitch * i_ytmp;
400 i_ynext = p_pic->p->i_pitch * i_y >> 6;
402 /* Draw until we reach the end of the line */
403 for( i_x = i_width ; i_x ; i_x -= i_len )
405 /* Get the RLE part, then draw as many lines as needed */
406 i_color = *p_source & 0x3;
407 i_len = i_xscale * ( *p_source++ >> 2 );
410 && ( i_x < i_x_start || i_x > i_x_end
411 || i_y < i_y_start || i_y > i_y_end ) )
416 switch( p_spu->p_sys->pi_alpha[ i_color ] )
422 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
423 i_ytmp += p_pic->p->i_pitch )
425 memset( p_dest - 4 * ( i_x >> 6 ) + i_ytmp,
427 4 * ( ( i_len >> 6 ) + 1 ) );
432 /* FIXME: we should do transparency */
433 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
434 i_ytmp += p_pic->p->i_pitch )
436 memset( p_dest - 4 * ( i_x >> 6 ) + i_ytmp,
438 4 * ( ( i_len >> 6 ) + 1 ) );
447 static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
448 const subpicture_t *p_spu, vlc_bool_t b_crop )
450 /* Common variables */
452 u16 *p_source = (u16 *)p_spu->p_sys->p_data;
459 int i_x_start, i_y_start, i_x_end, i_y_end;
461 p_dest = p_pic->p->p_pixels +
462 + ( p_spu->i_y + p_spu->i_height ) * p_pic->p->i_pitch // * bytes per line
463 + ( p_spu->i_x + p_spu->i_width ) * 2; // * bytes per pixel
465 i_x_start = p_spu->i_width - p_spu->p_sys->i_x_end;
466 i_y_start = (p_spu->i_height - p_spu->p_sys->i_y_end)
467 * p_pic->p->i_pitch / 2;
468 i_x_end = p_spu->i_width - p_spu->p_sys->i_x_start;
469 i_y_end = (p_spu->i_height - p_spu->p_sys->i_y_start)
470 * p_pic->p->i_pitch / 2;
472 /* Draw until we reach the bottom of the subtitle */
473 for( i_y = p_spu->i_height * p_pic->p->i_pitch / 2;
475 i_y -= p_pic->p->i_pitch / 2 )
477 /* Draw until we reach the end of the line */
478 for( i_x = p_spu->i_width ; i_x ; i_x -= i_len )
480 /* Get the RLE part, then draw the line */
481 i_color = *p_source & 0x3;
482 i_len = *p_source++ >> 2;
485 && ( i_x < i_x_start || i_x > i_x_end
486 || i_y < i_y_start || i_y > i_y_end ) )
491 switch( p_spu->p_sys->pi_alpha[ i_color ] )
497 for( i_cnt = 0; i_cnt < i_len; i_cnt++ )
501 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2,
502 p_spu->p_sys->pi_yuv[i_color][0], 1);
507 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 1,
509 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 3,
516 /* FIXME: we should do transparency */
517 for( i_cnt = 0; i_cnt < i_len; i_cnt++ )
521 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2,
522 p_spu->p_sys->pi_yuv[i_color][0], 1);
527 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 1,
529 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 3,