render.c

来自「VLC媒体播放程序」· C语言 代码 · 共 1,920 行 · 第 1/5 页

C
1,920
字号
/***************************************************************************** * render.c : Philips OGT and CVD (VCD Subtitle) blending routines. *            stuff from here might be pulled out, abstracted or used *            by DVD subtitles. ***************************************************************************** * Copyright (C) 2003, 2004 VideoLAN * $Id: render.c,v 1.29 2004/02/02 12:53:20 fenrir Exp $ * * Author: Rocky Bernstein <rocky@panix.com> *   based on code from:  *          Sam Hocevar <sam@zoy.org> *          Rudolf Cornelissen <rag.cornelissen@inter.nl.net> *          Roine Gustafsson <roine@popstar.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. *****************************************************************************//*#define TESTING_TRANSPARENCY 1*//***************************************************************************** * Preamble *****************************************************************************/#include <vlc/vlc.h>#include <vlc/vout.h>#include <vlc/decoder.h>#include "pixmap.h"#include "subtitle.h"#include "render.h"/* We use 4 bits for an transparency value: 0..15, 15 is completely   transparent and 0 completely opaque. Note that although SVCD allow   8-bits, for these routines pixels should previously have been be   scaled down to 4 bits (the range used by DVDs).*/#define TRANS_BITS (4)#define MAX_TRANS  ((1<<TRANS_BITS) - 1) #define TRANS_SCALEDOWN (8-TRANS_BITS)/* We use a fixed-point arithmetic in scaling ratios so that we   can use integer arithmetic and still get fairly precise   results. ASCALE is a left shift amount. */#define ASCALE 6  /* 2^6 = 32 *//* Horrible hack to get dbg_print to do the right thing */#define p_dec p_vout/**   Take two 8-bit RGB values and a transparency and do a weighted   average of them. The "weight" comes from i_trans which is in the   range 0..MAX_TRANS. To have greater precision using integer   arithmetic, the RGB values are scaled. The uint16_t cast below is   to make sure we don't overflow the product in the multiplication   (MAX_TRANS - i_trans) is the additive "inverse" of i_trans, i.e.   i_trans + (MAX_TRANS - i_trans) = MAX_TRANS. So the resulting sum   of rgb1*i_trans + rgb2*(MAX_TRANS-i_trans) will be scaled by   MAX_TRANS. To reduce the value back down to 8 bits, we shift by   TRANS_BITS, noting that 1 << TRANS_BITS is roughly   MAX_TRANS. (Actually it is MAX_TRANS - 1).*/#define avg_8bit_rgb(rgb_vout, rgb_sub, i_trans)                   \{                                                                  \   int i;                                                          \   for (i=0; i < RGB_SIZE; i++) {                                  \   rgb_vout[i] = ( (uint16_t) rgb_vout[i]*(MAX_TRANS-i_trans) +    \                   (uint16_t) rgb_sub [i]*i_trans ) >> TRANS_BITS; \   }                                                               \}/***************************************************************************** * Local prototypes *****************************************************************************/static void BlendI420( vout_thread_t *, picture_t *, const subpicture_t *,                        vlc_bool_t );static void BlendYUY2( vout_thread_t *p_vout, picture_t *p_pic,                        const subpicture_t *p_spu, vlc_bool_t b_crop );static void BlendRV16( vout_thread_t *p_vout, picture_t *p_pic,                       const subpicture_t *p_spu, vlc_bool_t b_crop,                       vlc_bool_t b_15bpp );static void BlendRV24( vout_thread_t *p_vout, picture_t *p_pic,                        const subpicture_t *p_spu, vlc_bool_t b_crop );static void BlendRV32( vout_thread_t *p_vout, picture_t *p_pic,                        const subpicture_t *p_spu, vlc_bool_t b_crop );static void BlendRGB2( vout_thread_t *p_vout, picture_t *p_pic,                        const subpicture_t *p_spu, vlc_bool_t b_crop );/***************************************************************************** * BlendSPU: blend a subtitle into a picture *****************************************************************************   This blends subtitles (a subpicture) into the underlying  picture. Subtitle data has been preprocessed as YUV + transparancy  or 4 bytes per pixel with interleaving of rows in the subtitle  removed.  *****************************************************************************/void VCDSubBlend( vout_thread_t *p_vout, picture_t *p_pic,		   const subpicture_t *p_spu ){    struct subpicture_sys_t *p_sys = p_spu->p_sys;      dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER), 	       "chroma %x", p_vout->output.i_chroma );    switch( p_vout->output.i_chroma )    {        /* I420 target, no scaling */        case VLC_FOURCC('I','4','2','0'):        case VLC_FOURCC('I','Y','U','V'):        case VLC_FOURCC('Y','V','1','2'):            BlendI420( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );            break;        /* RGB 555 - scaled */        case VLC_FOURCC('R','V','1','5'):            BlendRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop,                        VLC_TRUE );            break;                  case VLC_FOURCC('R','V','1','6'):            BlendRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop,                       /* Not sure under what conditions RV16 is really                          RV16 and not RV15.                        */#if 0                       VLC_FALSE );#else                       VLC_TRUE );#endif	    break;        /* RV24 target, scaling */        case VLC_FOURCC('R','V','2','4'):            BlendRV24( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );	    break;        /* RV32 target, scaling */        case VLC_FOURCC('R','V','3','2'):            BlendRV32( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );	    break;        /* NVidia overlay, no scaling */        case VLC_FOURCC('Y','U','Y','2'):            BlendYUY2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );	    break;        /* Palettized 8 bits per pixel (256 colors). Each           pixel is an uint8_t index in the palette           Used in ASCII Art.         */        case VLC_FOURCC('R','G','B','2'):            BlendRGB2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );          	    break;        default:            msg_Err( p_vout, "unknown chroma, can't render SPU" );            break;    }}/* Following functions are local *//*   YV12 format:    All Y samples are found first in memory as an array of bytes  (possibly with a larger stride for memory alignment), followed  immediately by all Cr (=U) samples (with half the stride of the Y  lines, and half the number of lines), then followed immediately by  all Cb (=V) samples in a similar fashion.*/static void BlendI420( vout_thread_t *p_vout, picture_t *p_pic,                        const subpicture_t *p_spu, vlc_bool_t b_crop ){  /* Common variables */  uint8_t *p_pixel_base_Y, *p_pixel_base_V, *p_pixel_base_U;  ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */  int i_x, i_y;  vlc_bool_t even_scanline = VLC_FALSE;  /* Crop-specific */  int i_x_start, i_y_start, i_x_end, i_y_end;  /* int i=0; */  const struct subpicture_sys_t *p_sys = p_spu->p_sys;    dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER), 	     "spu width x height: (%dx%d), (x,y)=(%d,%d), yuv pitch (%d,%d,%d)", 	     p_spu->i_width,  p_spu->i_height, p_spu->i_x, p_spu->i_y,	     p_pic->Y_PITCH, p_pic->U_PITCH, p_pic->V_PITCH );    p_pixel_base_Y = p_pic->p[Y_PLANE].p_pixels + p_spu->i_x                 + p_pic->p[Y_PLANE].i_pitch * p_spu->i_y;    p_pixel_base_U = p_pic->p[U_PLANE].p_pixels + p_spu->i_x/2                 + p_pic->p[U_PLANE].i_pitch * p_spu->i_y/2;    p_pixel_base_V = p_pic->p[V_PLANE].p_pixels + p_spu->i_x/2                 + p_pic->p[V_PLANE].i_pitch * p_spu->i_y/2;    i_x_start = p_sys->i_x_start;  i_y_start = p_pic->p[Y_PLANE].i_pitch * p_sys->i_y_start;    i_x_end   = p_sys->i_x_end;  i_y_end   = p_pic->p[Y_PLANE].i_pitch * p_sys->i_y_end;    p_source = (ogt_yuvt_t *)p_sys->p_data;    /* Draw until we reach the bottom of the subtitle */  for( i_y = 0;        i_y < p_spu->i_height * p_pic->p[Y_PLANE].i_pitch ;       i_y += p_pic->p[Y_PLANE].i_pitch )    {      uint8_t *p_pixel_base_Y_y = p_pixel_base_Y + i_y;      uint8_t *p_pixel_base_U_y = p_pixel_base_U + i_y/4;      uint8_t *p_pixel_base_V_y = p_pixel_base_V + i_y/4;      i_x = 0;      if ( b_crop ) {        if ( i_y > i_y_end ) break;        if (i_x_start) {          i_x = i_x_start;          p_source += i_x_start;        }      }      even_scanline = !even_scanline;      /* Draw until we reach the end of the line */      for( ; i_x < p_spu->i_width; i_x++, p_source++ )	{	  if( b_crop ) {            /* FIXME: y cropping should be dealt with outside of this loop.*/            if ( i_y < i_y_start) continue;            if ( i_x > i_x_end )	    {	      p_source += p_spu->i_width - i_x;              break;	    }          }#ifdef TESTING_TRANSPARENCY          if (p_source->s.t == MAX_TRANS) p_source->s.t >>= 1;#endif	  switch( p_source->s.t )	    {	    case 0: 	      /* Completely transparent. Don't change pixel. */	      break;	      	    case MAX_TRANS:	      {		/* Completely opaque. Completely overwrite underlying		   pixel with subtitle pixel. */				/* This is the location that's going to get changed.*/		uint8_t *p_pixel_Y = p_pixel_base_Y_y + i_x;				*p_pixel_Y = p_source->plane[Y_PLANE];		if ( even_scanline && i_x % 2 == 0 ) {		  uint8_t *p_pixel_U = p_pixel_base_U_y + i_x/2;		  uint8_t *p_pixel_V = p_pixel_base_V_y + i_x/2;		  *p_pixel_U = p_source->plane[U_PLANE];		  *p_pixel_V = p_source->plane[V_PLANE];		}				break;	      }	      	    default:	      {		/* Blend in underlying subtitle pixel. */				/* This is the location that's going to get changed. */		uint8_t *p_pixel_Y = p_pixel_base_Y_y + i_x;		/* This is the weighted part of the subtitle. The		   color plane is 8 bits and transparancy is 4 bits so		   when multiplied we get up to 12 bits.		 */		uint16_t i_sub_color_Y = 		  (uint16_t) ( p_source->plane[Y_PLANE] *			       (uint16_t) (p_source->s.t) );		/* This is the weighted part of the underlying pixel.		   For the same reasons above, the result is up to 12		   bits.  However since the transparancies are		   inverses, the sum of i_sub_color and i_pixel_color		   will not exceed 12 bits.		*/		uint16_t i_pixel_color_Y = 		  (uint16_t) ( *p_pixel_Y * 			       (uint16_t) (MAX_TRANS - p_source->s.t) ) ;				/* Scale the 12-bit result back down to 8 bits. A		   precise scaling after adding the two components,		   would divide by one less than a power of 2. However		   to simplify and speed things we use a power of		   2. This means the boundaries (either all		   transparent and all opaque) aren't handled properly.		   But we deal with them in special cases above. */		*p_pixel_Y = ( i_sub_color_Y + i_pixel_color_Y ) >> TRANS_BITS;		if ( even_scanline && i_x % 2 == 0 ) {		  uint8_t *p_pixel_U = p_pixel_base_U_y + i_x/2                    - p_pic->p[U_PLANE].i_pitch / 2;		  uint8_t *p_pixel_V = p_pixel_base_V_y + i_x/2                    - p_pic->p[V_PLANE].i_pitch / 2;		  uint16_t i_sub_color_U = 		    (uint16_t) ( p_source->plane[U_PLANE] *				 (uint16_t) (p_source->s.t) );		  		  uint16_t i_sub_color_V = 		    (uint16_t) ( p_source->plane[V_PLANE] *				 (uint16_t) (p_source->s.t) );		  uint16_t i_pixel_color_U = 		    (uint16_t) ( *p_pixel_U * 				 (uint16_t) (MAX_TRANS - p_source->s.t) ) ;		  uint16_t i_pixel_color_V = 		    (uint16_t) ( *p_pixel_V * 				 (uint16_t) (MAX_TRANS - p_source->s.t) ) ;		  *p_pixel_U = ( i_sub_color_U + i_pixel_color_U )>>TRANS_BITS;		  *p_pixel_V = ( i_sub_color_V + i_pixel_color_V )>>TRANS_BITS;		}		break;	      }	      	    }	}    }}/*  YUY2 Format:  Data is found in memory as an array of bytes in which the first byte  contains the first sample of Y, the second byte contains the first  sample of Cb (=U), the third byte contains the second sample of Y,  the fourth byte contains the first sample of Cr (=V); and so  on. Each 32-bit word then contains information for two contiguous  horizontal pixels, two 8-bit Y values plus a single Cb and Cr which  spans the two pixels.*/#define BYTES_PER_PIXEL 4static void BlendYUY2( vout_thread_t *p_vout, picture_t *p_pic,                        const subpicture_t *p_spu, vlc_bool_t b_crop ){  /* Common variables */  uint8_t *p_pixel_base;  /* This is the where the subtitle pixels come from */  ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;  ogt_yuvt_t *p_source_end = (ogt_yuvt_t *)p_spu->p_sys->p_data + 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?