YUV与RGB格式转换的教训与思考(一)

      实际上YUV格式种类繁多,很容易让人弄混,不同的格式,在不同的设备上显示,效果也不相同。
 
一、标准公式:
       可以参考标准网站,下面只列常用的。
1.  模拟电视PAL/NTSC制式的视频格式转换:
 
 
2. 标准清晰度电视(SDTV)的转换(基于ITU-R BT.601): 
       请注意,YUV要有全范围和非全范围值的区别。啥叫全范围咧? 一个像素,理论上值在0-255间,就是full-range,否则就是
nofull-range.
        
       下面这2个矩阵就是nofull-range 转换(因为值Y值在16..235,CbCr在16..240间):
     
       
 
         full-range的转换公式:
 
3. 高清电视HDTV转换(ITU-R BT.709):
 
二、工程优化
    公式采用浮点运算,众所周知,浮点运算肯定比整型运算慢上很多,所以工程上的第一步,就是将浮点运算整数化:
 
 
namespace vpsdk
{
#define R_INDEX 2
#define G_INDEX 1
#define B_INDEX 0
#define C_BPP3  3
 
#define pix_clip(pix) pix<0?0:pix>255?255:pix
 
static void bgr_to_y_row_c(uint8_t *src,uint8_t *ybuf,int width) {
  int offset = 0;
  for(int y=0; y<width; y++) {
    int r = src[offset+R_INDEX];
   int g = src[offset+G_INDEX];
   int b = src[offset+B_INDEX];
   int pix = (r*5983 +20127*g+2032*b+524288)>>15;
   if( pix < 16 ) pix = 16;
   else if( pix > 235 ) pix = 235;
   ybuf[y] = (uint8_t)pix;
   offset += C_BPP3;
  }
}
 
static void bgr_to_full_y_row_c(uint8_t *src,uint8_t *ybuf,int width) {
  int offset = 0;
  for(int y=0; y<width; y++) {
    int r = src[offset+R_INDEX];
   int g = src[offset+G_INDEX];
   int b = src[offset+B_INDEX];
   int pix = (r*9798 +19235*g+3736*b)>>15;
   ybuf[y] = (uint8_t)pix_clip(pix);
   offset += C_BPP3;
  }
}
 
static void bgr_to_uv_row_c(uint8_t *src,uint8_t *ubuf,uint8_t *vbuf,int stride,int width) {
  for(int y=0,ii=0; y<width; y+=2,ii++) {
    int r[4],g[4],b[4];
    r[0] = (int)src[y*C_BPP3+R_INDEX];
   g[0] = (int)src[y*C_BPP3+G_INDEX];
   b[0] = (int)src[y*C_BPP3+B_INDEX];
 
    r[1] = (int)src[(y+1)*C_BPP3+R_INDEX];
   g[1] = (int)src[(y+1)*C_BPP3+G_INDEX];
   b[1] = (int)src[(y+1)*C_BPP3+B_INDEX];
 
    r[2] = (int)src[y*C_BPP3+R_INDEX+stride];
   g[2] = (int)src[y*C_BPP3+G_INDEX+stride];
   b[2] = (int)src[y*C_BPP3+B_INDEX+stride];
 
    r[3] = (int)src[(y+1)*C_BPP3+R_INDEX+stride];
   g[3] = (int)src[(y+1)*C_BPP3+G_INDEX+stride];
   b[3] = (int)src[(y+1)*C_BPP3+B_INDEX+stride];
 
   int uu=0,vv=0;
   for(int k=0; k<4; k++) {
     uu += (((-3298*r[k]-11094*g[k]+14392*b[k])+4194304)>>15);
     vv += (((14392*r[k]-13073*g[k]-1320*b[k])+4194304)>>15);
   }
 
   uu /= 4;
   vv /= 4;
 
   ubuf[ii] = (uint8_t)pix_clip(uu);
   vbuf[ii] = (uint8_t)pix_clip(vv);
  }
}
 
// rgb -> yuv :
// y = 0   + 0.299*r + 0.587*g + 0.114*b;
// u = 128 - 0.169*r - 0.331*g + 0.500*b ;
// v = 128 + 0.500*r - 0.419*g - 0.081*b ;
// int : *32768
// y = 0   + 9798*r + 19235*g + 3736*b;
// u = 4194304 - 5538*r - 10846*g + 16384*b ;
// v = 4194304 + 16384*r- 13730*g - 2654*b ;
//------------------------------------------------
static void bgr_to_full_uv_row_c(uint8_t *src,uint8_t *ubuf,uint8_t *vbuf,int stride,int width) {
  for(int y=0,ii=0; y<width; y+=2,ii++) {
    int r[4],g[4],b[4];
    r[0] = (int)src[y*C_BPP3+R_INDEX];
   g[0] = (int)src[y*C_BPP3+G_INDEX];
   b[0] = (int)src[y*C_BPP3+B_INDEX];
 
    r[1] = (int)src[(y+1)*C_BPP3+R_INDEX];
   g[1] = (int)src[(y+1)*C_BPP3+G_INDEX];
   b[1] = (int)src[(y+1)*C_BPP3+B_INDEX];
 
    r[2] = (int)src[y*C_BPP3+R_INDEX+stride];
   g[2] = (int)src[y*C_BPP3+G_INDEX+stride];
   b[2] = (int)src[y*C_BPP3+B_INDEX+stride];
 
    r[3] = (int)src[(y+1)*C_BPP3+R_INDEX+stride];
   g[3] = (int)src[(y+1)*C_BPP3+G_INDEX+stride];
   b[3] = (int)src[(y+1)*C_BPP3+B_INDEX+stride];
 
   int uu=0,vv=0;
   for(int k=0; k<4; k++) {
     uu += (((-5538*r[k]-10846*g[k]+16384*b[k])+4194304)>>15);
     vv += (((16384*r[k]-13730*g[k]-2654*b[k])+4194304)>>15);
   }
 
   uu /= 4;
   vv /= 4;
 
   if( uu < 16 ) uu = 16;
   else if( uu > 240.0 ) uu = 240;
 
   if( vv < 16 ) vv = 16;
   else if( vv > 240.0 ) vv = 240;
 
   ubuf[ii] = (uint8_t)uu;
   vbuf[ii] = (uint8_t)vv;
  }
}
 
/////////////////////////////////////////////////////////////////////////////////////////////
//For digital component video the color format YCbCr is used. For standard definition TV applications
//    (SDTV) the following equation describes the color conversion from RGB to YCbCr
//     (according to ITU-R BT.601):
//y = y-16         (16..235)
//u = u - 128      (16..240)
//v = v - 128      (16..240)
//r = 1.164 * y + 0.00    + 1.596 * v
//g = 1.164 * y - 0.392*u - 0.813 * v
//b = 1.164 * y + 2.017*u + 0.00 * v;
/////////////////////////////////////////////////////////////////////////////////////////////
//    rgb -> yuv :
//  y = 16  + 0.257*r + 0.504 *g + 0.098 * b;     rgb(0..255)
//  u = 128 - 0.148*r - 0.291 *g + 0.439 * b;     y(16..235)
//  v = 128 + 0.439*r - 0.368 *g - 0.071 * b;     uv(16..240)
//
/////////////////////////////////////////////////////////////////////////////////////////////
static void yuv_to_bgr_row_c(uint8_t *ybuf,uint8_t *ubuf,uint8_t *vbuf,uint8_t *bgr,int width)
{
  for(int x=0; x<width; x++) {
    int y = (ybuf[x]  - 16);
    int u = ubuf[x/2] - 128;
   int v = vbuf[x/2] - 128;
   y = y * 38142;
   bgr[x*3+0] = pix_clip((y + 69206*u)>>15);
   bgr[x*3+1] = pix_clip((y - 6980*u - 17465*v)>>15);
   bgr[x*3+2] = pix_clip((y + 58753*v)>>15);
  }
}
 
 
/////////////////////////////////////////////////////////////////////////////////////////////
//o convert a full-range YCbCr color into RGB is described by the following equation
//y = y - 0         (0..255)
//u = u - 128       (0..255)
//v = v - 128       (0..255)
//r = 1.0 * y + 0.00    + 1.4 * v
//g = 1.0 * y - 0.343*u - 0.711 * v
//b = 1.0 * y + 1.765*u + 0.00 * v;
// int : 32768
//
//r = 32768 * y + 0.00    + 45875 * v
//g = 32768 * y - 11239*u - 23298 * v
//b = 32768 * y + 57836*u + 0.00 * v;
//
/////////////////////////////////////////////////////////////////////////////////////////////
// rgb -> yuv :
// y = 0   + 0.299*r + 0.587*g + 0.114*b;
// u = 128 - 0.169*r - 0.331*g + 0.500*b ;
// v = 128 + 0.500*r - 0.419*g - 0.081*b ;
// int : *32768
// y = 0   + 9798*r + 19235*g + 3736*b;
// u = 4194304 - 5538*r - 10846*g + 16384*b ;
// v = 4194304 + 16384*r- 13730*g - 2654*b ;
//------------------------------------------------
//
/////////////////////////////////////////////////////////////////////////////////////////////
static void full_yuv_to_bgr_row_c(uint8_t *ybuf,uint8_t *ubuf,uint8_t *vbuf,uint8_t *bgr,int width)
{
  for(int x=0; x<width; x++) {
    int y = ybuf[x];
    int u = ubuf[x/2] - 128;
   int v = vbuf[x/2] - 128;
   y = y * 32768;
   bgr[x*3+2] = pix_clip((y + 45875*v)>>15);
   bgr[x*3+1] = pix_clip((y - 11239*u - 23298*v)>>15);
   bgr[x*3+0] = pix_clip((y + 57836*u)>>15);
  }
}
 
static void nv12_to_bgr_row_c(uint8_t *ybuf,uint8_t *uvbuf,uint8_t *bgr,int width)
{
  for(int x=0; x<width; x++) {
    int y = (ybuf[x]  - 16);
    int u = uvbuf[x/2] - 128;
   int v = uvbuf[x/2+1] - 128;
   y = y * 38142;
   bgr[x*3]   = pix_clip((y + 69206*u)>>15);
   bgr[x*3+1] = pix_clip((y - 6980*u - 17465*v)>>15);
   bgr[x*3+2] = pix_clip((y + 58753*v)>>15);
  }
}
 
static void full_nv12_to_bgr_row_c(uint8_t *ybuf,uint8_t *uvbuf,uint8_t *bgr,int width)
{
  for(int x=0; x<width; x++) {
    int y = ybuf[x];
    int u = uvbuf[x/2] - 128;
   int v = uvbuf[x/2+1] - 128;
   y = y * 32768;
   bgr[x*3+2] = pix_clip((y + 45875*v)>>15);
   bgr[x*3+1] = pix_clip((y - 11239*u - 23298*v)>>15);
   bgr[x*3+0] = pix_clip((y + 57836*u)>>15);
  }
}
 
typedef void (*fn_nv12_to_bgr_row)(uint8_t *ybuf,uint8_t *uvbuf,uint8_t *bgra,int width);
typedef void (*fn_yuv_to_bgr_row)(uint8_t *ybuf,uint8_t *ubuf,uint8_t *vbuf,uint8_t *bgr,int width);
typedef void (*fn_bgr_to_y_row)(uint8_t *src,uint8_t *ybuf,int width);
typedef void (*fn_bgr_to_uv_row)(uint8_t *src,uint8_t *ubuf,uint8_t *vbuf,int stride,int width);
 
static void bgr_to_yv12_c(uint8_t *src, int stride,
              uint8_t *ybuf, int ystride,
              uint8_t *ubuf, int ustride,
              uint8_t *vbuf, int vstride,
              int width, int height,int full)
{
  int iheight = abs(height);
  int istride = height<0?-stride:stride;
  if( height < 0 ) src = src + (iheight-1)*stride;
 
  fn_bgr_to_y_row  func_y  = full?bgr_to_full_y_row_c:bgr_to_y_row_c;
  fn_bgr_to_uv_row func_uv = full?bgr_to_full_uv_row_c:bgr_to_uv_row_c;
 
  for(int y=0; y<iheight-1; y+=2) {
    func_y(src,ybuf,width);
    func_y(src+istride,ybuf+ystride,width);
    func_uv(src,ubuf,vbuf,istride,width);
    src  += (istride*2);
    ybuf += (ystride*2);
    ubuf += ustride;
    vbuf += vstride;
  }
  if( iheight & 1 ) {
    func_uv(src,ubuf,vbuf,0,width/2);
    func_y(src,ybuf,width);
  }
}
 
static void yv12_to_bgr_c(uint8_t *ybuf,int ystride,
        uint8_t *ubuf,int ustride,
        uint8_t *vbuf,int vstride,
        uint8_t *bgr, int stride,
        int width, int height,int full)
{
  int iheight = abs(height);
  int istride = stride;
  if( height < 0 ) {
    istride = -stride;
    bgr = bgr + (iheight-1)*stride;
  }
 
  fn_yuv_to_bgr_row func = full?full_yuv_to_bgr_row_c:yuv_to_bgr_row_c;
 
  for(int y=0; y<iheight-1; y+=2) {
    func(ybuf,ubuf,vbuf,bgr,width);
   func(ybuf+ystride,ubuf,vbuf,bgr+istride,width);
    bgr += (2*istride);
    ybuf += 2*ystride;
    ubuf += ustride;
    vbuf += vstride;
  }
 
  if( iheight & 1 ) {
    func(ybuf,ubuf,vbuf,bgr,width);
  }
}
 
static void nv12_to_bgr_c(uint8_t *ybuf,int ystride,
         uint8_t *uvbuf,int uvstride,
        uint8_t *bgr, int stride,
        int width, int height,int full)
{
  int iheight = abs(height);
  int istride = stride;
  if( height < 0 ) {
    istride = -stride;
    bgr = bgr + (iheight-1)*stride;
  }
 
  fn_nv12_to_bgr_row func = full?full_nv12_to_bgr_row_c:nv12_to_bgr_row_c;
 
  for(int y=0; y<iheight-1; y+=2) {
    func(ybuf,uvbuf,bgr,width);
   func(ybuf+ystride,uvbuf,bgr+istride,width);
    bgr += (2*istride);
    ybuf += 2*ystride;
    uvbuf += uvstride;
  }
 
  if( iheight & 1 ) {
    func(ybuf,uvbuf,bgr,width);
  }
}
 
bool vp_convert::i420_to_bgr(int width,int height,uint8_t *src,video_frame* dst,int full) {
  uint8_t *ybuf = src;
  uint8_t *ubuf = src+width*height;
  uint8_t *vbuf = src+width*height*5/4;
  yv12_to_bgr_c(ybuf,width,ubuf,width>>1,vbuf,width>>1,dst->m_data[0],dst->m_line[0],width,height,full);  
  return true;
}
 
bool vp_convert::yv12_to_bgr(int width,int height,uint8_t *src,video_frame* dst,int full) {
  uint8_t *ybuf = src;
  uint8_t *vbuf = src+width*height;
  uint8_t *ubuf = src+width*height*5/4;
  yv12_to_bgr_c(ybuf,width,ubuf,width>>1,vbuf,width>>1,dst->m_data[0],dst->m_line[0],width,height,full);
  return true;
}
 
bool vp_convert::nv12_to_bgr(int width,int height,uint8_t *src,video_frame* dst,int full) {
 uint8_t *ybuf = src;
 uint8_t *uvbuf = src+width*height;
  nv12_to_bgr_c(ybuf,width,uvbuf,width,dst->m_data[0],dst->m_line[0],width,height,full);
  return true;
}
 
bool vp_convert::bgr_to_i420(video_frame* src,video_frame *dst,int full) {
  bgr_to_yv12_c(src->m_data[0],src->m_line[0],
     dst->m_data[0], dst->m_line[0],
     dst->m_data[1], dst->m_line[1],
     dst->m_data[2], dst->m_line[2],
     src->m_width,dst->m_height,full);
  return true;
}
 
}
 
 

posted on 2016-01-08 15:29  zwshare  阅读(1312)  评论(0)    收藏  举报

导航