/*****************************************************************************
* 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;
}
网友评论