colorformatcvt

2021-08-10  本文已影响0人  可不期诺Cappuccino
/*****************************************************************************
 * colorspace.c: misc colorspace conversion functions
 *****************************************************************************
 * $Id: colorspace.c,v 1.16 2005/08/11 23:25:01 pingus77 Exp $
 *****************************************************************************
 * Copyright (C) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
 *
 * 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.
 *****************************************************************************
 *
 * misc colorspace conversion functions
 *
 *****************************************************************************/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "colorspace.h"
#include "memcpy.h"
#include "strtab.h"
extern int debug;

struct STRTAB video_fmt_names[] = {
  {VIDEO_RGB03,"rgb3"},
  {VIDEO_RGB04b,"rgb4b"},
  {VIDEO_RGB08,"rgb8"},
  {VIDEO_RGB08b,"rgb8b"},
  {VIDEO_RGB15,"rgb15"},
  {VIDEO_RGB16,"rgb16"},
  {VIDEO_RGB24,"rgb24"},
  {VIDEO_RGB24B,"rgb24b"},
  {VIDEO_RGB32,"rgb32"},
  {VIDEO_RGB32B,"rgb32b"},
  {VIDEO_RGB32P,"rgb32p"},
  {VIDEO_RGB15X,"rgb15x"},
  {VIDEO_RGB16X,"rgb16x"},
  {VIDEO_RGB24X,"rgb24x"},
  {VIDEO_RGB32X,"rgb32x"},
  {VIDEO_RGB32PX,"rgb32px"},
  {VIDEO_HI240,"hi240"},
  {VIDEO_GRAY1,"gray1"},
  {VIDEO_GRAY1X,"gray1x"},
  {VIDEO_GRAY4,"gray4"},
  {VIDEO_GRAY8,"gray8"},
  {VIDEO_YUYV, "yuyv"},
  {VIDEO_UYVY, "uyvy"},
  {VIDEO_YUV420,"yuv420"},
  {VIDEO_YVU420,"yvu420"},
  {VIDEO_Y41P, "y41p"},
  {VIDEO_YVU410, "yvu410"},
  {VIDEO_YUV410, "yuv410"},
  {VIDEO_YUV422P, "yuv422p"},
  {VIDEO_YUV411P, "yuv411p"},
  {VIDEO_NV12, "nv12"},
  {-1, NULL}
};

static void
rgb4b_to_rgb32 (unsigned char *dest, unsigned char *s, int w, int h)
{
  int i, *d = (int *)dest;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = ((c & 0x3) << (16+6)) | (((c >> 2)&0x1) << (8+7)) | (c>>3<<7);
  }
}

static void
rgb32_to_rgb4b (unsigned char *d, unsigned char *src, int w, int h)
{
  int i, *s = (int *)src;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = (c>>(16+6)) | ((c&0xFF00)>>(8+7)<<2) | ((c & 0xFF)>>7<<3);
  }
}

static void
rgb8b_to_rgb32 (unsigned char *dest, unsigned char *s, int w, int h)
{
  int i, *d = (int *)dest;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = ((c & 0x7) << (16+5)) | (((c >> 3)&0x7) << (8+5)) | (c>>6<<6);
  }
}

static void
rgb32_to_rgb8b (unsigned char *d, unsigned char *src, int w, int h)
{
  int i, *s = (int *)src;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = (c>>(16+5)) | ((c&0xFF00)>>(8+5)<<3) | ((c & 0xFF)>>6<<6);
  }
}

static void
rgb8_to_rgb32 (unsigned char *dest, unsigned char *s, int w, int h)
{
  int i, *d = (int *)dest;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = ((c >> 6) << (16+6)) | (((c >> 3)&0x7) << (8+5)) | ((c & 0x7) << 5);
  }
}

static void
rgb32_to_rgb8 (unsigned char *d, unsigned char *src, int w, int h)
{
  int i, *s = (int *)src;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = ((c>>(16+6))<<6) | ((c&0xFF00)>>(8+5)<<3) | ((c & 0xFF)>>5);
  }
}

static void
rgb15_to_rgb32 (unsigned char *dest, unsigned char *src, int w, int h)
{
  int i, *d = (int *)dest;
  short *s = (short *)src;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = ((c >> 10) << (16+3)) | (((c >> 5)&0x1F) << (8+3)) | ((c & 0x1F) << 3);
  }
}

static void
rgb32_to_rgb15 (unsigned char *dest, unsigned char *src, int w, int h)
{
  int i, *s = (int *)src;
  short *d = (short *)dest;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = ((c>>(16+3))<<10) | ((c&0xFF00)>>(8+3)<<5) | ((c & 0xFF)>>3);
  }
}

static void
rgb16_to_rgb32 (unsigned char *dest, unsigned char *src, int w, int h)
{
  int i, *d = (int *)dest;
  short *s = (short *)src;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = ((c >> 11) << (16+3)) | (((c >> 5)&0x3F) << (8+2)) | ((c & 0x1F) << 3);
  }
}

static void
rgb32_to_rgb16 (unsigned char *dest, unsigned char *src, int w, int h)
{
  int i, *s = (int *)src;
  short *d = (short *)dest;
  for (i=w*h; i>0; i--, d++, s++) {
    unsigned int c=*s;
    *d = ((c>>(16+3))<<11) | ((c&0xFF00)>>(8+2)<<5) | ((c & 0xFF)>>3);
  }
}

static void
rgb24_to_rgb32 (unsigned char *dest, unsigned char *src, int w, int h)
{
  int i = w * h;

  while (i--)
    {
#ifdef WORDS_BIGENDIAN
      *(dest++) = 0;
#endif
      *(dest++) = *(src++);
      *(dest++) = *(src++);
      *(dest++) = *(src++);
#ifndef WORDS_BIGENDIAN
      *(dest++) = 0;
#endif
    }
}

static void
rgb32_to_rgb24 (unsigned char *dest, unsigned char *src, int w, int h)
{
  int i = w * h;

  while (i--)
    {
#ifdef WORDS_BIGENDIAN
      src++;
#endif
      *(dest++) = *(src++);
      *(dest++) = *(src++);
      *(dest++) = *(src++);
#ifndef WORDS_BIGENDIAN
      src++;
#endif
    }
}

static void gray1_to_gray8(unsigned char *d, unsigned char *s, int w, int h) {
   int x,y,z,dpad=((w+31)/32*4-w/8);
  /* the width must be multiple of 32, 
     (just assumed to be multiple of 4 in xdtv, see x11.c) */
  for(y=h;y>0;y--) {
    for(x=w;x>7;x-=8,s++,d+=8)
      for(z=0;z<8;z++)
#ifdef WORDS_BIGENDIAN
    d[z]=(*s&(1<<(8-z)))?255:0;
#else
        d[z]=(*s&(1<<z))?255:0;
#endif
    s+=dpad;
  }
}

static void gray8_to_gray1(unsigned char *d, unsigned char *s, int w, int h) {
  int x,y,dpad=((w+31)/32*4-w/8);
  /* the width must be multiple of 32, 
     (just assumed to be multiple of 4 in xdtv, see x11.c) */
  for(y=h;y>0;y--) {
    for(x=w;x>7;x-=8,d++,s+=8)
#ifdef WORDS_BIGENDIAN
      *d=(s[7]>>7)|(s[6]>>7<<1)|(s[5]>>7<<2)|(s[4]>>7<<3)|(s[3]>>7<<4)|(s[2]>>7<<5)
    |(s[1]>>7<<6)|(s[0]>>7<<7);
#else
      *d=(s[0]>>7)|(s[1]>>7<<1)|(s[2]>>7<<2)|(s[3]>>7<<3)|(s[4]>>7<<4)|(s[5]>>7<<5)
    |(s[6]>>7<<6)|(s[7]>>7<<7);
#endif
    d+=dpad;
  }
}

static void gray4_to_gray8(unsigned char *d, unsigned char *s, int w, int h) {
  int i;
  for (i=w*h; i>0; i--, d++, s++) *d=*s<<4;
}

static void gray8_to_gray4(unsigned char *d, unsigned char *s, int w, int h) {
  int i;
  for (i=w*h; i>0; i--, d++, s++) *d=*s>>4;
}

static void yuv420_to_gray8(unsigned char *dest, unsigned char *src, int width, int height) {
  fast_memcpy(dest, src, width*height);
}

static void gray8_to_yuv420(unsigned char *dest, unsigned char *src, int width, int height) {
  int size=width*height;
  fast_memcpy(dest, src, size);
  dest+=size; size/=4; memset(dest, 128, size);
  dest+=size; memset(dest, 128, size);
}

/* rgb4 is xdtv-specific ! (just for fun :>)*/
static void rgb3_to_rgb32(unsigned char *dd, unsigned char *s, int w, int h) {
  unsigned int *d=(unsigned int *)dd;
  int i;
  for (i=w*h; i>0; i--, d++, s++)
    *d=((*s&1)<<(7-0))|((*s&2)<<(15-1))|((*s&4)<<(23-2));
}
static void rgb32_to_rgb3(unsigned char *d, unsigned char *ss, int w, int h) {
  unsigned int *s=(unsigned int *)ss;
  int i;
  for (i=w*h; i>0; i--, d++, s++)
    *d = ((s[0]>>7)&1)|(((s[0]>>15)&1)<<1)|(((s[0]>>23)&1)<<2);
}
  
static void hi240_to_rgb32(unsigned char *dest, unsigned char *src, int w, int h) {
  static int *rgb32_conv=NULL;
  int i;
  int *dest2=(int *)dest;
  if(rgb32_conv==NULL) {
    rgb32_conv=(int *) malloc(256*sizeof(int));
    for(i=0;i<225;i++) {
      int r=((i/5)%5)*255.0/4+0.5;
      int g=(i/25)*255.0/8+0.5;
      int b=(i%5)*255.0/4+0.5;
      rgb32_conv[16+i]=(b<<0)|(g<<8)|(r<<16);
    }
  }
  for(i=w*h;i>0;i--,dest2++,src++) *dest2=rgb32_conv[*src];
}

static void rgb32_to_hi240(unsigned char *d, unsigned char *s, int w, int h) {
  int i;
  for (i=w*h; i>0; i--, d++, s+=4) {
#ifdef WORDS_BIGENDIAN
    *d = 16 + s[3]/52 + s[1]/52*5 + s[2]/29*25;
#else
    *d = 16 + s[0]/52 + s[2]/52*5 + s[1]/29*25;
#endif
  }
}

static void yvu420_yuv420(unsigned char *d, unsigned char *s, int w, int h) {
  unsigned char *as, *bs, *ad, *bd;
  int t = w*h / 4;
  as = s + t*4;
  bs = as+ t;
  ad = d + t*4;
  bd = ad+ t;
  fast_memcpy(d,  s, t*4);
  fast_memcpy(ad, bs, t);
  fast_memcpy(bd, as, t);
}

static void rgb32_rgb32b(unsigned char *d, unsigned char *s, int w, int h) {
  int t = 4*w, y;
  s +=  t * (h - 1);
  for (y = h; y > 0; y--) { fast_memcpy(d, s, t); d += t; s -= t; }
}

static void rgb24_rgb24b(unsigned char *d, unsigned char *s, int w, int h) {
  int t = 3*w, y;
  s +=  t * (h - 1);
  for (y = h; y > 0; y--) { fast_memcpy(d, s, t); d += t; s -= t; }
}

static void swap1bpp32(unsigned char *dest, unsigned char *src, int w, int h) {
  int *d=(int *)dest,*s=(int *)src,ss,dd,i,j;
  for(i=w*h/32; i>0; i--,s++,d++) {
    ss=*s;dd=0;
    for(j=0;j<32;j++) if(ss&(1<<j)) dd|=(1<<(32-j));
    *d=dd;
  }
}

static void swap16bpp(unsigned char *d, unsigned char *s, int w, int h) {
  int i;
  //swab(d, s, 2*w*h);
  for(i=w*h; i>0; i--,s+=2,d+=2) { d[0]=s[1]; d[1]=s[0];}
}

static void swap24bpp(unsigned char *d, unsigned char *s, int w, int h) {
  int i;
  for(i=w*h; i>0; i--,s+=3,d+=3) { d[0]=s[2]; d[1]=s[1]; d[2]=s[0];}
}

static void swap32bpp(unsigned char *d, unsigned char *s, int w, int h) {
  int i;
  for(i=w*h; i>0; i--,s+=4,d+=4) { d[0]=s[3]; d[1]=s[2]; d[2]=s[1]; d[3]=s[0];}
}

void swap24(unsigned char *m, int t) {
  int i;
  unsigned char c;
  for(i=t; i>0; i--, m+=3) { c=m[0]; m[0]=m[2]; m[2]=c; } 
}

static void yuyv_to_yuv420 (unsigned char *d, unsigned char *s, int w, int h)
{
  int a, b;
  unsigned char *y, *u, *v;
  y = d;
  u = y + w * h;
  v = u + w * h / 4;

  for (a = h; a > 0; a -= 2)
    {
      for (b = w; b > 0; b -= 2)
        { *(y++) = *(s++); *(u++) = *(s++); *(y++) = *(s++); *(v++) = *(s++); }
      for (b = w; b > 0; b -= 2)
        { *(y++) = *(s++);  s++;  *(y++) = *(s++); s++; }
    }
}

        vx_imagepatch_addressing_t input_addr;
        vx_rectangle_t rect;
        vx_map_id input_id;
        void *input_ptr;

        rect.start_x = 0;
        rect.start_y = 0;
        rect.end_x = obj->input_image_width;
        rect.end_y = obj->input_image_height;
        vxMapImagePatch(obj->input_img[0], &rect, 0, &input_id, &input_addr, &input_ptr,
                        VX_READ_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X);

        vx_imagepatch_addressing_t out_addr;
        vx_map_id out_id;
        void *out_ptr;

        rect.start_x = 0;
        rect.start_y = 0;
        rect.end_x = obj->output_image_width;
        rect.end_y = obj->output_image_height;
        vxMapImagePatch(obj->output_img[0], &rect, 0, &out_id, &out_addr, &out_ptr,
                        VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X);

        unsigned char *pin = input_ptr;
        unsigned char *pout = out_ptr;
        yuv420_to_uyvy()

static void yuv420_to_yuyv(unsigned char *d, unsigned char *s,int w, int h) 
{
  unsigned char *y,*u,*v,*u2,*v2;
  int a, b;
  y = s;
  u = y + w * h;
  v = u + w * h / 4;
  for (b = h; b > 0; b -= 2) {
    u2 = u; v2 = v;
    for (a = w; a > 0; a -= 2)
      { *(d++) = *(y++); *(d++) = *(u++); *(d++) = *(y++); *(d++) = *(v++);}
    u = u2; v = v2;
    for (a = w; a > 0; a -= 2)
      { *(d++) = *(y++); *(d++) = *(u++); *(d++) = *(y++); *(d++) = *(v++);}
  }
}

static void yuv420_to_uyvy(unsigned char *d, unsigned char *s,int w, int h) 
{
  unsigned char *y,*u,*v,*u2,*v2;
  int a, b;
  y = s;
  u = y + w * h;
  v = u + w * h / 4;
  for (b = h; b > 0; b -= 2) {
    u2 = u; v2 = v;
    for (a = w; a > 0; a -= 2)
    { 
        *(d++) = *(u++); 
        *(d++) = *(y++); 
        *(d++) = *(v++);
        *(d++) = *(y++); 
    }
    u = u2; v = v2;
    for (a = w; a > 0; a -= 2)
    { 
        *(d++) = *(u++); 
        *(d++) = *(y++); 
        *(d++) = *(v++);
        *(d++) = *(y++);  
    }
  }
}

static void yuv420_to_yuyv(unsigned char *d, unsigned char *s,int w, int h) {
  unsigned char *y,*u,*v,*u2,*v2;
  int a, b;
  y = s;
  u = y + w * h;
  v = u + w * h / 4;
  for (b = h; b > 0; b -= 2) {
    u2 = u; v2 = v;
    for (a = w; a > 0; a -= 2)
      { *(d++) = *(y++); *(d++) = *(u++); *(d++) = *(y++); *(d++) = *(v++);}
    u = u2; v = v2;
    for (a = w; a > 0; a -= 2)
      { *(d++) = *(y++); *(d++) = *(u++); *(d++) = *(y++); *(d++) = *(v++);}
  }
}

/* NOT VERIFIED */
/* w must be a multiple of 8 ! */
static void y41p_to_yuyv(unsigned char *d, unsigned char *s,int w, int h) {
  int i;
  for(i=w*h;i>0;i-=8,s+=12,d+=16) {
    d[5]=d[1]=s[0]; d[0]=s[1]; d[7]=d[3]=s[2]; d[2]=s[3]; d[9]=d[13]=s[4]; d[4]=s[5];
    d[11]=d[15]=s[6]; d[6]=s[7]; d[8]=s[8]; d[10]=s[9]; d[12]=s[10]; d[14]=s[11];
  }
}

/* NOT VERIFIED */
static void yuyv_to_y41p(unsigned char *d, unsigned char *s,int w, int h) {
  int i;
  for(i=w*h;i>0;i-=8,s+=16,d+=12) {
    d[0]=s[1]; d[1]=s[0];  d[2]=s[3];  d[3]=s[2];  d[4]=s[9];  d[5]=s[4]; 
    d[6]=s[11]; d[7]=s[6];  d[8]=s[8];  d[9]=s[10];  d[10]=s[12];  d[11]=s[14];
  } 
}

static void y410_to_y420(unsigned char *d, unsigned char *s,int w, int h) {
  int t=w*h, i, x, y, w4=w/4;
  fast_memcpy(d, s, t);
  s+=t; d+=t;
  for(i=2;i>0;i--)
    for(y=h;y>0;y-=4) {
      unsigned char *s0=s;
      for(x=w4;x>0;x--) {
    *(d++)=*s; *(d++)=*(s++);
      }
      s=s0;
      for(x=w4;x>0;x--) {
    *(d++)=*s; *(d++)=*(s++);
      }
    }
}

static void y420_to_y410(unsigned char *d, unsigned char *s,int w, int h) {
  int i, t=w*h, x, y, w4=w/4;
  fast_memcpy(d, s, t);
  s+=t; d+=t;
  for(i=2;i>0;i--)
    for(y=h;y>0;y-=4) {
      for(x=w4;x>0;x--) {
    *(d++)=*s; s+=2;
      }
      s+=2*w4;;
    }
}

static void yuyv_to_yuv422p (unsigned char *d, unsigned char *s, int w, int h) {
  int a, b;
  unsigned char *y, *u, *v;
  y = d;
  u = y + w * h;
  v = u + w * h / 2;
  for (a = h; a > 0; a--)
    for (b = w; b > 0; b -= 2)
      { *(y++) = *(s++); *(u++) = *(s++); *(y++) = *(s++); *(v++) = *(s++); }
}

static void yuv422p_to_yuyv(unsigned char *d, unsigned char *s,int w, int h) {
  unsigned char *y,*u,*v;
  int a, b;
  y = s;
  u = y + w * h;
  v = u + w * h / 2;
  for (b = h; b > 0; b --)
    for (a = w; a > 0; a -= 2)
      { *(d++) = *(y++); *(d++) = *(u++); *(d++) = *(y++); *(d++) = *(v++);}
}


static void yuv411p_to_yuv422p (unsigned char *d, unsigned char *s, int w, int h) {
  int i, t=w*h;
  fast_memcpy(d, s, t);
  d+=t; s+=t;
  for(i=t/2;i>0;i--) {
    *(d++)=*s; *(d++)=*(s++);
  }
}

static void yuv422p_to_yuv411p(unsigned char *d, unsigned char *s,int w, int h) {
  int i, t=w*h;
  fast_memcpy(d, s, t);
  d+=t; s+=t;
  for(i=t/2;i>0;i--) {
    *(d++)=*s; s+=2;
  }
}

/* NOT VERIFIED */
static void nv12_to_yuv420 (unsigned char *d, unsigned char *s, int w, int h) {
  int i, t=w*h;
  unsigned char *y, *u, *v;
  y = d;
  u = y + t;
  v = u + t / 4;
  fast_memcpy(d, s, t);
  s += t;
  for(i=t/4;i>0;i--) {
    *(u++)=*(s++); *(v++)=*(s++);
  }
}

/* NOT VERIFIED */
static void yuv420_to_nv12(unsigned char *d, unsigned char *s,int w, int h) {
  int i, t=w*h;
  unsigned char *y,*u,*v;
  y = s;
  u = y + t;
  v = u + t / 4;
  fast_memcpy(d, s, t);
  d += t;
  for(i=t/4;i>0;i--) {
    *(d++)=*(u++); *(d++)=*(v++);
  }
}



/******** RGB to YUV functions **********/
#ifdef WORDS_BIGENDIAN
#define RGBDO {s++; r=*(s++); g=*(s++); b=(*s++);}
#else
#define RGBDO {b=(*s++); g=*(s++); r=*(s++); s++;}
#endif
#define Y(r,g,b) (((16829*r+31913*g+6416*b)>>16)+16)
#define U(r,g,b) (((-9750*r-19148*g+28898*b)>>16)+128)
#define V(r,g,b) (((28898*r-24199*g-4699*b)>>16)+128)
static void rgb32_to_yuv420(unsigned char *d, unsigned char *s, int w, int h) {
  int aa, bb;
  unsigned char *y, *u, *v, r, g, b;
  y = d;
  u = y + w * h;
  v = u + w * h / 4;
  for (aa = h; aa > 0; aa -= 2) {
    for (bb = w; bb > 0; bb -= 2) {
      RGBDO; *(y++)=Y(r,g,b); *(u++)=U(r,g,b);
      RGBDO; *(y++)=Y(r,g,b);
    }
    for (bb = w; bb > 0; bb -= 2) {
      RGBDO; *(y++)=Y(r,g,b);
      RGBDO; *(y++)=Y(r,g,b); *(v++)=V(r,g,b);
    }
  }
}
static void rgb32_to_yuyv(unsigned char *d, unsigned char *s, int w, int h) {
  int i;
  for(i=w*h; i>0;i-=2,s+=8,d+=4) {
    unsigned char r,g,b;
#ifdef WORDS_BIGENDIAN
    r=s[1]; g=s[2]; b=s[3]; 
#else
    b=s[0]; g=s[1]; r=s[2]; 
#endif
    d[0] = Y(r,g,b); d[1] = U(r,g,b);
#ifdef WORDS_BIGENDIAN
    r=s[5]; g=s[6]; b=s[7]; 
#else
    b=s[4]; g=s[5]; r=s[6];
#endif
    d[2] = Y(r,g,b); d[3] = V(r,g,b);
  }
}

static void rgb24_to_yuyv(unsigned char *d, unsigned char *s, int w, int h) {
  int i;
  for(i=w*h; i>0;i-=2,s+=6,d+=4) {
    unsigned char r,g,b;
#ifdef WORDS_BIGENDIAN
    r=s[0]; g=s[1]; b=s[2];
#else
    b=s[0]; g=s[1]; r=s[2]; 
#endif
    d[0] = Y(r,g,b); d[1] = U(r,g,b);
#ifdef WORDS_BIGENDIAN
    r=s[3]; g=s[4]; b=s[5]; 
#else
    b=s[3]; g=s[4]; r=s[5];
#endif
    d[2] = Y(r,g,b); d[3] = V(r,g,b);
  }
}

/****** YUV to RGB functions *******/
#define sat(x,max) if(x<0) x=0; if(x>max) x=max;
static inline void pix_yuv_to_rgb(unsigned char y, unsigned char u, unsigned char v,
                  unsigned char *r, unsigned char *g, unsigned char *b) {
  int y2,r2,g2,b2;
  y2=76309*y;
  r2=(-14556884+y2+104187*v)>>16; sat(r2,255); *r=r2;
  g2=(8842838+y2-25564*u-53060*v)>>16; sat(g2,255); *g=g2;
  b2=(-18076354+y2+131683*u)>>16; sat(b2,255); *b=b2;
}
#ifdef WORDS_BIGENDIAN
#define RGBDO2 {pix_yuv_to_rgb(*y,*u,*v,&d[1],&d[2],&d[3]);}
#else
#define RGBDO2 {pix_yuv_to_rgb(*y,*u,*v,&d[2],&d[1],&d[0]);}
#endif
static void yuv420_to_rgb32(unsigned char *d, unsigned char *s, int w, int h) {
  unsigned char *y, *u, *v, *u2, *v2;
  int a,b;
  y = s;
  u = y + w * h;
  v = u + w * h / 4;
  for (a = h; a > 0; a -= 2) {
    u2 = u; v2 = v;
    for (b = w; b > 0; b -= 2) {
      RGBDO2; y++; d+=4;
      RGBDO2; y++; u++; v++; d+=4;
    }
    u = u2; v = v2;
    for (b = w; b > 0; b -= 2) {
      RGBDO2; y++; d+=4;
      RGBDO2; y++; u++; v++; d+=4;
    }
  }
}

static void yuyv_to_rgb32(unsigned char *d, unsigned char *s, int width, int height) {
  int i;
  for(i=width*height;i>0;i-=2,s+=4,d+=8) {
#ifdef WORDS_BIGENDIAN
    pix_yuv_to_rgb(s[0],s[1],s[3],&d[1],&d[2],&d[3]);
    pix_yuv_to_rgb(s[2],s[1],s[3],&d[5],&d[6],&d[7]);
#else
    pix_yuv_to_rgb(s[0],s[1],s[3],&d[2],&d[1],&d[0]);
    pix_yuv_to_rgb(s[2],s[1],s[3],&d[6],&d[5],&d[4]);
#endif
  }
}

/** end YUV to RGB functions **/

/******************************************************
 **** The exported functions 
 ********************************************/

int size_img(video_fmt f, int width, int height) {
  /* width should be a multiple of 8 to be sure....
     and height a multiple of 2 */
  switch(f) { 
  case VIDEO_GRAY1:
  case VIDEO_GRAY1X: return ((width+31)/32)*4*height;
  case VIDEO_GRAY4:
  case VIDEO_RGB03:
  case VIDEO_RGB04b:  return width*height;
  case VIDEO_GRAY8:
  case VIDEO_RGB08:
  case VIDEO_RGB08b:
  case VIDEO_HI240:  return width*height;
  case VIDEO_RGB15X:
  case VIDEO_RGB15:
  case VIDEO_RGB16X:
  case VIDEO_RGB16:  return width*height*2;
  case VIDEO_RGB24:
  case VIDEO_RGB24X:
  case VIDEO_RGB24B: return width*height*3;
  case VIDEO_RGB32:
  case VIDEO_RGB32P:
  case VIDEO_RGB32X:
  case VIDEO_RGB32PX:
  case VIDEO_RGB32B: return width*height*4;
  case VIDEO_UYVY:
  case VIDEO_YUYV :  
  case VIDEO_YUV422P: return width*height*2;
  case VIDEO_Y41P:
  case VIDEO_YUV420:
  case VIDEO_YVU420: 
  case VIDEO_YUV411P: 
  case VIDEO_NV12: return width*height*3/2;
  case VIDEO_YUV410:
  case VIDEO_YVU410: return width*height*5/4;
  case MAX_VIDEO_FMT:
  case VIDEO_NOFORMAT: fprintf(stderr,"SHOULD NOT HAPPEN\n"); exit(1);
  }
  return 0;
}


void* convert1(char *src, video_fmt f_src, video_fmt f_dest,
           int width, int height) {
  static void *bufs[MAX_VIDEO_FMT];
  if(debug>=2)
    fprintf(stderr, "convert1 %s -> %s %dx%d\n", 
        int_to_str (f_src,video_fmt_names),
        int_to_str (f_dest,video_fmt_names), width, height);
  if(f_src==f_dest) return src;
  /* during the pipe it is constant in fact... */
  bufs[f_dest]=realloc(bufs[f_dest],size_img(f_dest,width,height));
  convert2(src,f_src,bufs[f_dest],f_dest,width,height);
  return bufs[f_dest];
}

typedef void (*convertf) (unsigned char *d, unsigned char *s, int w, int h);
typedef struct {convertf conv;video_fmt f_src; video_fmt f_dst; int cost;} convertf2;
static convertf2 convs[]= {
  {gray1_to_gray8,  VIDEO_GRAY1,  VIDEO_GRAY8,   20},
  {gray8_to_gray1,  VIDEO_GRAY8,  VIDEO_GRAY1,   40},
  {gray4_to_gray8,  VIDEO_GRAY4,  VIDEO_GRAY8,   20},
  {gray8_to_gray4,  VIDEO_GRAY8,  VIDEO_GRAY4,   40},
  {rgb3_to_rgb32,   VIDEO_RGB03,  VIDEO_RGB32,   20},
  {rgb32_to_rgb3,   VIDEO_RGB32,  VIDEO_RGB03,   40},
  {rgb15_to_rgb32,  VIDEO_RGB15,  VIDEO_RGB32,   10},
  {rgb32_to_rgb15,  VIDEO_RGB32,  VIDEO_RGB15,   15},
  {rgb16_to_rgb32,  VIDEO_RGB16,  VIDEO_RGB32,   10},
  {rgb32_to_rgb16,  VIDEO_RGB32,  VIDEO_RGB16,   15},
  {rgb24_to_rgb32,  VIDEO_RGB24,  VIDEO_RGB32,    5},
  {rgb32_to_rgb24,  VIDEO_RGB32,  VIDEO_RGB24,    5},
  {yuv420_to_gray8, VIDEO_YUV420, VIDEO_GRAY8,  200}, //too much info lost
  {gray8_to_yuv420, VIDEO_GRAY8,  VIDEO_YUV420,   4},
  {hi240_to_rgb32,  VIDEO_HI240,  VIDEO_RGB32,   20},
  {rgb32_to_hi240,  VIDEO_RGB32,  VIDEO_HI240,   40}, //too much info lost
  {rgb8_to_rgb32,   VIDEO_RGB08,  VIDEO_RGB32,   10},
  {rgb32_to_rgb8,   VIDEO_RGB32,  VIDEO_RGB08,   38}, //too much info lost
  {rgb8b_to_rgb32,  VIDEO_RGB08b, VIDEO_RGB32,   10},
  {rgb32_to_rgb8b,  VIDEO_RGB32,  VIDEO_RGB08b,   38},
  {rgb4b_to_rgb32,  VIDEO_RGB04b, VIDEO_RGB32,   20},
  {rgb32_to_rgb4b,  VIDEO_RGB32,  VIDEO_RGB04b,   40},
  {yuyv_to_yuv420,  VIDEO_YUYV,   VIDEO_YUV420,   5},
  {yuv420_to_yuyv,  VIDEO_YUV420, VIDEO_YUYV,     5},
  {rgb32_to_yuv420, VIDEO_RGB32,  VIDEO_YUV420,  32},
  {rgb24_to_yuyv,   VIDEO_RGB24,  VIDEO_YUYV,    30},
  {rgb32_to_yuyv,   VIDEO_RGB32,  VIDEO_YUYV,    31},
  {yuv420_to_rgb32, VIDEO_YUV420, VIDEO_RGB32,   31},
  {yuyv_to_rgb32,   VIDEO_YUYV,   VIDEO_RGB32,   32},
  {yvu420_yuv420,   VIDEO_YVU420, VIDEO_YUV420,   4},
  {yvu420_yuv420,   VIDEO_YUV420, VIDEO_YVU420,   4},
  {rgb32_rgb32b,    VIDEO_RGB32,  VIDEO_RGB32B,   4},
  {rgb32_rgb32b,    VIDEO_RGB32B, VIDEO_RGB32,    4},
  {rgb24_rgb24b,    VIDEO_RGB24,  VIDEO_RGB24B,   4},
  {rgb24_rgb24b,    VIDEO_RGB24B, VIDEO_RGB24,    4},
  {swap16bpp,       VIDEO_YUYV,   VIDEO_UYVY,     6},
  {swap16bpp,       VIDEO_UYVY,   VIDEO_YUYV,     6},
  {swap16bpp,       VIDEO_RGB16,  VIDEO_RGB16X,   6},
  {swap16bpp,       VIDEO_RGB16X, VIDEO_RGB16,    6},
  {swap16bpp,       VIDEO_RGB15,  VIDEO_RGB15X,   6},
  {swap16bpp,       VIDEO_RGB15X, VIDEO_RGB15,    6},
  {swap24bpp,       VIDEO_RGB24,  VIDEO_RGB24X,   6},
  {swap24bpp,       VIDEO_RGB24X, VIDEO_RGB24,    6},
  {swap32bpp,       VIDEO_RGB32,  VIDEO_RGB32X,   6},
  {swap32bpp,       VIDEO_RGB32X, VIDEO_RGB32,    6},
  {swap32bpp,       VIDEO_RGB32P, VIDEO_RGB32PX,  6},
  {swap32bpp,       VIDEO_RGB32PX,VIDEO_RGB32P,   6},
  {rgb24_to_rgb32,  VIDEO_RGB24X, VIDEO_RGB32PX,  5},
  {rgb32_to_rgb24,  VIDEO_RGB32PX,VIDEO_RGB24X,   5},
  {swap1bpp32,      VIDEO_GRAY1,  VIDEO_GRAY1X,   5},
  {swap1bpp32,      VIDEO_GRAY1X, VIDEO_GRAY1,    5},
  {y41p_to_yuyv,    VIDEO_Y41P,   VIDEO_YUYV,    10},
  {yuyv_to_y41p,    VIDEO_YUYV,   VIDEO_Y41P,    10},
  {y410_to_y420,    VIDEO_YUV410, VIDEO_YUV420,  8},
  {y420_to_y410,    VIDEO_YUV420, VIDEO_YUV410,  8},
  {y410_to_y420,    VIDEO_YVU410, VIDEO_YVU420,  8},
  {y420_to_y410,    VIDEO_YVU420, VIDEO_YVU410,  8},
  {yuyv_to_yuv422p, VIDEO_YUYV,   VIDEO_YUV422P, 8},
  {yuv422p_to_yuyv, VIDEO_YUV422P,VIDEO_YUYV,    8},
  {yuv411p_to_yuv422p, VIDEO_YUV411P,   VIDEO_YUV422P, 8},
  {yuv422p_to_yuv411p, VIDEO_YUV422P,VIDEO_YUV411P,    8},
  {nv12_to_yuv420,  VIDEO_NV12,   VIDEO_YUV420,   5},
  {yuv420_to_nv12,  VIDEO_YUV420, VIDEO_NV12,     5},
  {NULL, 0, 0, 100}
};

static convertf2 **firstconv=NULL;
/* compute the best intermediate format by Dijkstra's algorithm */
static void initfirstconv(void) {
  /* direct cannot be put in cost_tab because it could be possible
     that the direct link is not the fastest 
     (probably by a fault in the costs...) */
  int direct[MAX_VIDEO_FMT][MAX_VIDEO_FMT];
  int cost_tab[MAX_VIDEO_FMT][MAX_VIDEO_FMT],i,j,dest;
  convertf2 *c,*c2;
  firstconv=calloc(MAX_VIDEO_FMT*MAX_VIDEO_FMT,sizeof(convertf2*));
  for(i=1;i<MAX_VIDEO_FMT;i++)
    for(j=1;j<MAX_VIDEO_FMT;j++) {
      direct[i][j]=-1;
      if(i==j)
    cost_tab[i][j]=0;
      else
    cost_tab[i][j]=-1;
    }
  c=convs;while(c->conv) {direct[c->f_src][c->f_dst]=c->cost;c++;}
  for(dest=1;dest<MAX_VIDEO_FMT;dest++) {
    int i0,j0;
    do {
      int m=10000000;
      i0=j0=-1;
      for(i=1;i<MAX_VIDEO_FMT;i++)
    if(cost_tab[i][dest]!=-1)
      for(j=1;j<MAX_VIDEO_FMT;j++)
        if(direct[j][i]!=-1 && cost_tab[j][dest]==-1
           && direct[j][i]+cost_tab[i][dest]<m)
          {m=direct[j][i]+cost_tab[i][dest]; i0=i; j0=j;}
      if(i0!=-1) {
    cost_tab[j0][dest]=m;
    c2=convs; while(c2->f_src!=j0 || c2->f_dst!=i0) c2++;
    firstconv[j0+dest*MAX_VIDEO_FMT]=c2;
      }
    } while(i0!=-1);
  }
  if(debug>=2) {
    fprintf(stderr, "conversion costs:\n");
    for(i=1;i<MAX_VIDEO_FMT;i++)
      for(j=1;j<MAX_VIDEO_FMT;j++)
    fprintf(stderr, "%s -> %s: %d (by %s)\n", int_to_str(i, video_fmt_names),
        int_to_str(j, video_fmt_names), cost_tab[i][j],
        firstconv[i+j*MAX_VIDEO_FMT]!=NULL ?
        int_to_str(firstconv[i+j*MAX_VIDEO_FMT]->f_dst, video_fmt_names):"-");
  }
}

static int convert_cost(video_fmt f_src, video_fmt f_dest) {
  convertf2 *c;
  if(f_src==f_dest) return 0;
  if(firstconv==NULL) initfirstconv();
  c=firstconv[f_src+MAX_VIDEO_FMT*f_dest];
  if(c==NULL) return 1000000;
  return c->cost+convert_cost(c->f_dst,f_dest);
}


void convert2(char *src, video_fmt f_src, char *dest, video_fmt f_dest,
          int width, int height) {
  int size;
  convertf2 *c;
  if(debug>=2) {
    fprintf(stderr, "convert2 %s -> %s %dx%d\n", 
        int_to_str (f_src,video_fmt_names),
        int_to_str (f_dest,video_fmt_names), width, height);
  }
  size=size_img(f_src,width,height);
  if(f_src==f_dest) {
    fast_memcpy(dest,src,size);
    return;
  }
  if(firstconv==NULL) initfirstconv();
  c=firstconv[f_src+MAX_VIDEO_FMT*f_dest];
  if(c==NULL) {
    fprintf(stderr, "convert2 %s -> %s not implemented\n", 
        int_to_str (f_src,video_fmt_names),
        int_to_str (f_dest,video_fmt_names));
    //exit (1);
    return;
  }
  if(c->f_dst==f_dest)
    c->conv((unsigned char*)dest, (unsigned char*)src, width, height);
  else {
    void *mem=convert1(src, f_src, c->f_dst, width, height);
    convert2(mem, c->f_dst, dest, f_dest, width, height);
  }
  return;
}

/* takes an array of video_fmt */
int setpreferred_list(video_fmt formats[], video_fmt prefered[]) {
  int available[MAX_VIDEO_FMT], i;
  for(i=0;i<MAX_VIDEO_FMT;i++) available[i]=0;
  for(i=0;formats[i]!=0;i++) available[formats[i]]=1;
  return setpreferred(available,prefered);
}

/* takes an array of booleans */
int setpreferred(int available[], video_fmt prefered[]) {
  int i;
  video_fmt def=0;
  if(debug) fprintf(stderr, "*** asked for prefered conversions ***\n");
  for(i=1;i<MAX_VIDEO_FMT;i++)
    if(available[i]) {def=i; break;}
  if(def==0) return 0;
  for(i=1;i<MAX_VIDEO_FMT;i++) {
    int cost=100000,j;
    prefered[i]=def;  // unneeded if there are all the conversions
    for(j=1;j<MAX_VIDEO_FMT;j++)
      if(available[j] && convert_cost(j,i)<cost) {
    cost=convert_cost(j,i);
    prefered[i]=j;
      }
    if(debug)
      fprintf(stderr,"%s --> %s\n", int_to_str(i, video_fmt_names),
          int_to_str(prefered[i], video_fmt_names));
  }
  if(debug) fprintf(stderr, "*** end prefered conversions ***\n");
  return 1;
}


上一篇下一篇

猜你喜欢

热点阅读