422 lines
No EOL
12 KiB
C
422 lines
No EOL
12 KiB
C
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static int cubic_coeff[]={//32-taps
|
|
0, 256, 0, 0,
|
|
-3, 255, 4, 0,
|
|
-6, 254, 10, 0,
|
|
-9, 251, 16, 0,
|
|
-11, 247, 23, -1,
|
|
-13, 242, 31, -2,
|
|
-15, 236, 39, -3,
|
|
-16, 229, 48, -4,
|
|
-17, 222, 58, -5,
|
|
-18, 214, 68, -6,
|
|
-18, 205, 78, -8,
|
|
-18, 196, 89, -9,
|
|
-18, 186, 100, -10,
|
|
-17, 176, 111, -12,
|
|
-17, 166, 122, -13,
|
|
-16, 155, 133, -14,
|
|
-15, 144, 144, -15,
|
|
-14, 133, 155, -16,
|
|
-13, 122, 166, -17,
|
|
-12, 111, 176, -17,
|
|
-10, 100, 186, -18,
|
|
-9, 89, 196, -18,
|
|
-8, 78, 205, -18,
|
|
-6, 68, 214, -18,
|
|
-5, 58, 222, -17,
|
|
-4, 48, 229, -16,
|
|
-3, 39, 236, -15,
|
|
-2, 31, 242, -13,
|
|
-1, 23, 247, -11,
|
|
0, 16, 251, -9,
|
|
0, 10, 254, -6,
|
|
0, 4, 255, -3,
|
|
};
|
|
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
|
#define CLIP(a,i,s) (((a) > (s)) ? (s) : MAX(a,i))
|
|
|
|
|
|
typedef struct ISP_CTX
|
|
{
|
|
int SC_dst_format; //0-420 1-422 2-444
|
|
int SC_hor_filter_type;
|
|
int width;
|
|
int height;
|
|
int SC_dst_width;
|
|
int SC_dst_height;
|
|
int outpicsize;
|
|
int SC_luma_hor_ratio;
|
|
int SC_luma_ver_ratio;
|
|
int SC_luma_ver_init_phase;
|
|
int SC_luma_hor_init_phase;
|
|
int SC_chroma_hor_init_phase;
|
|
int SC_chroma_ver_init_phase;
|
|
int SC_HOR_FILTER_COEFF0[16][4];//4-taps
|
|
int SC_VER_FILTER_COEFF[32][2];//2-taps
|
|
}ISP_CTX;
|
|
|
|
|
|
void SC_hor_filter(ISP_CTX *ispctx,unsigned char *dst_buf,unsigned char *src_ptr,int src_width,int dst_width,int ratio,int init_phase,int filter_type,int isLuma)
|
|
{
|
|
int j;
|
|
int base_pixel,hphase,r;
|
|
unsigned char x[4],*td_buf;
|
|
int *C;
|
|
|
|
td_buf = (unsigned char *)malloc(dst_width+4);
|
|
|
|
for(j=0;j<dst_width;j++)
|
|
{
|
|
base_pixel = (j*ratio+init_phase)>>8;
|
|
hphase = j*ratio+init_phase - (base_pixel<<8);
|
|
|
|
if(base_pixel-1<0)
|
|
x[0] = src_ptr[0];
|
|
else if(base_pixel-1>=src_width)
|
|
x[0] = src_ptr[src_width-1];
|
|
else
|
|
x[0] = src_ptr[base_pixel-1];
|
|
|
|
if(base_pixel<0)
|
|
x[1] = src_ptr[0];
|
|
else if(base_pixel>=src_width)
|
|
x[1] = src_ptr[src_width-1];
|
|
else
|
|
x[1] = src_ptr[base_pixel];
|
|
|
|
if(base_pixel+1<0)
|
|
x[2] = src_ptr[0];
|
|
else if(base_pixel+1>=src_width)
|
|
x[2] = src_ptr[src_width-1];
|
|
else
|
|
x[2] = src_ptr[base_pixel+1];
|
|
|
|
if(base_pixel+2<0)
|
|
x[3] = src_ptr[0];
|
|
else if(base_pixel+2>=src_width)
|
|
x[3] = src_ptr[src_width-1];
|
|
else
|
|
x[3] = src_ptr[base_pixel+2];
|
|
|
|
if(filter_type==0)
|
|
{//4-taps
|
|
C = ispctx->SC_HOR_FILTER_COEFF0[hphase>>4];
|
|
r = x[0]*C[0] + x[1]*C[1] + x[2]*C[2] + x[3]*C[3];
|
|
r += 128;
|
|
r >>= 8;
|
|
}
|
|
td_buf[j+2] = CLIP(r,0,255);
|
|
}
|
|
td_buf[0] = td_buf[1] = td_buf[2];
|
|
td_buf[2+dst_width] = td_buf[3+dst_width] = td_buf[1+dst_width];
|
|
|
|
memcpy(dst_buf,td_buf+2,dst_width);
|
|
|
|
free(td_buf);
|
|
}
|
|
|
|
void do_scaler(ISP_CTX *ispctx,unsigned char * psrc, unsigned char * pdst, int src_w, int src_h, int dst_w, int dst_h, int fmt, int align)
|
|
{
|
|
int i,j,*C,r;
|
|
unsigned char *scline_buf[2],*lastline,*curline;
|
|
int line_num[2],base_line,base_linep1;
|
|
unsigned char *dst_ptr,*CbPtr,*CrPtr,*DstBuf;
|
|
int vphase,hratio,vratio,init_vphase;
|
|
int src_height,src_width,dst_width,dst_height;
|
|
int align_width,sub_num,cro_align_width,cro_sub_num;
|
|
|
|
scline_buf[0] = (unsigned char *)malloc(ispctx->SC_dst_width*2);
|
|
scline_buf[1] = scline_buf[0] + ispctx->SC_dst_width;
|
|
DstBuf = (unsigned char *)malloc(ispctx->outpicsize*3);
|
|
//DstBuf = (unsigned char *)VirtualAlloc(0,ispctx->outpicsize*3,MEM_COMMIT,PAGE_READWRITE);
|
|
dst_ptr = DstBuf;
|
|
|
|
//calculate luminance
|
|
line_num[0] = line_num[1] = -1;
|
|
vratio = ispctx->SC_luma_ver_ratio;
|
|
init_vphase = (ispctx->SC_luma_ver_init_phase);
|
|
align_width = (src_w + align - 1) & (~(align - 1));
|
|
sub_num = align_width - src_w;
|
|
cro_align_width = ((src_w>>1) + align/2 - 1) & (~(align/2 - 1));
|
|
cro_sub_num = cro_align_width - (src_w>>1);
|
|
|
|
for(i=0; i<ispctx->SC_dst_height; i++)
|
|
{
|
|
base_line = (i*vratio+init_vphase)>>8;
|
|
vphase = (i*vratio+init_vphase) - (base_line<<8);
|
|
|
|
{
|
|
if(base_line >= ispctx->height)
|
|
base_line = ispctx->height-1;
|
|
|
|
base_linep1 = base_line+1;
|
|
if(base_linep1 >= ispctx->height)
|
|
base_linep1 = ispctx->height-1;
|
|
}
|
|
|
|
if(base_line == line_num[0])
|
|
{
|
|
lastline = scline_buf[0];
|
|
}
|
|
else if(base_line == line_num[1])
|
|
{
|
|
lastline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
lastline = scline_buf[0];
|
|
line_num[0] = base_line;
|
|
|
|
//need to fill
|
|
SC_hor_filter(ispctx,lastline,psrc+base_line*align_width,ispctx->width,ispctx->SC_dst_width,ispctx->SC_luma_hor_ratio,ispctx->SC_luma_hor_init_phase,0,1);
|
|
}
|
|
|
|
if(base_linep1 == line_num[0])
|
|
{
|
|
curline = scline_buf[0];
|
|
}
|
|
else if(base_linep1 == line_num[1])
|
|
{
|
|
curline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
if(base_line == line_num[0])
|
|
{
|
|
line_num[1] = base_linep1;
|
|
curline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
line_num[0] = base_linep1;
|
|
curline = scline_buf[0];
|
|
}
|
|
|
|
//need to fill
|
|
|
|
SC_hor_filter(ispctx,curline,psrc+base_linep1*align_width,ispctx->width,ispctx->SC_dst_width,ispctx->SC_luma_hor_ratio,ispctx->SC_luma_hor_init_phase,0,1);
|
|
}
|
|
|
|
//vertical filter
|
|
C = ispctx->SC_VER_FILTER_COEFF[vphase>>3];
|
|
for(j=0;j<ispctx->SC_dst_width;j++)
|
|
{
|
|
r = lastline[j]*C[0] + curline[j]*C[1];
|
|
r += 128;
|
|
r >>= 8;
|
|
*dst_ptr++ = CLIP(r,0,255);
|
|
}
|
|
dst_ptr += sub_num;
|
|
}
|
|
|
|
//decide the chroma aspect ratio
|
|
switch(fmt)
|
|
{//0-yuv420, 1-yuv422, 2-yvu420, 3-yvu422,4-yuyv422, 5-32x32,8-argb8888, 9-rgba8888, 10-abgr8888, 11-bgra8888
|
|
case 0:
|
|
{//src is 4:2:0, dst is 4:2:0
|
|
hratio = ispctx->SC_luma_hor_ratio;
|
|
vratio = ispctx->SC_luma_ver_ratio;
|
|
dst_width = ispctx->SC_dst_width>>1;
|
|
dst_height = ispctx->SC_dst_height>>1;
|
|
}
|
|
src_width = ispctx->width>>1;
|
|
src_height = ispctx->height>>1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//calculate chrominance Cb
|
|
CbPtr = psrc + align_width*ispctx->height;
|
|
line_num[0] = line_num[1] = -1;
|
|
vratio = ispctx->SC_luma_ver_ratio;
|
|
init_vphase = (ispctx->SC_chroma_ver_init_phase);
|
|
for(i=0;i<dst_height;i++)
|
|
{
|
|
base_line = (i*vratio+init_vphase)>>8;
|
|
vphase = (i*vratio+init_vphase) - (base_line<<8);
|
|
|
|
{
|
|
if(base_line >= src_height)
|
|
base_line = src_height-1;
|
|
|
|
base_linep1 = base_line+1;
|
|
if(base_linep1 >= src_height)
|
|
base_linep1 = src_height-1;
|
|
}
|
|
|
|
if(base_line == line_num[0])
|
|
{
|
|
lastline = scline_buf[0];
|
|
}
|
|
else if(base_line == line_num[1])
|
|
{
|
|
lastline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
lastline = scline_buf[0];
|
|
line_num[0] = base_line;
|
|
|
|
//need to fill
|
|
SC_hor_filter(ispctx,lastline,CbPtr+base_line*cro_align_width,src_width,dst_width,hratio,ispctx->SC_chroma_hor_init_phase,0,0);
|
|
}
|
|
|
|
if(base_linep1 == line_num[0])
|
|
{
|
|
curline = scline_buf[0];
|
|
}
|
|
else if(base_linep1 == line_num[1])
|
|
{
|
|
curline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
if(base_line == line_num[0])
|
|
{
|
|
line_num[1] = base_linep1;
|
|
curline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
line_num[0] = base_linep1;
|
|
curline = scline_buf[0];
|
|
}
|
|
|
|
//need to fill
|
|
SC_hor_filter(ispctx,curline,CbPtr+base_linep1*cro_align_width,src_width,dst_width,hratio,ispctx->SC_chroma_hor_init_phase,0,0);
|
|
}
|
|
|
|
//vertical filter
|
|
C = ispctx->SC_VER_FILTER_COEFF[vphase>>3];
|
|
for(j=0;j<dst_width;j++)
|
|
{
|
|
r = lastline[j]*C[0] + curline[j]*C[1];
|
|
r += 128;
|
|
r >>= 8;
|
|
*dst_ptr++ = CLIP(r,0,255);
|
|
}
|
|
dst_ptr += cro_sub_num;
|
|
}
|
|
|
|
CrPtr = CbPtr + cro_align_width*src_height;
|
|
line_num[0] = line_num[1] = -1;
|
|
vratio = ispctx->SC_luma_ver_ratio;
|
|
init_vphase = (ispctx->SC_chroma_ver_init_phase);
|
|
for(i=0;i<dst_height;i++)
|
|
{
|
|
base_line = (i*vratio+init_vphase)>>8;
|
|
vphase = (i*vratio+init_vphase) - (base_line<<8);
|
|
|
|
|
|
{
|
|
if(base_line >= src_height)
|
|
base_line = src_height-1;
|
|
|
|
base_linep1 = base_line+1;
|
|
if(base_linep1 >= src_height)
|
|
base_linep1 = src_height-1;
|
|
}
|
|
|
|
if(base_line == line_num[0])
|
|
{
|
|
lastline = scline_buf[0];
|
|
}
|
|
else if(base_line == line_num[1])
|
|
{
|
|
lastline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
lastline = scline_buf[0];
|
|
line_num[0] = base_line;
|
|
|
|
//need to fill
|
|
SC_hor_filter(ispctx,lastline,CrPtr+base_line*cro_align_width,src_width,dst_width,hratio,ispctx->SC_chroma_hor_init_phase,0,0);
|
|
}
|
|
|
|
if(base_linep1 == line_num[0])
|
|
{
|
|
curline = scline_buf[0];
|
|
}
|
|
else if(base_linep1 == line_num[1])
|
|
{
|
|
curline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
if(base_line == line_num[0])
|
|
{
|
|
line_num[1] = base_linep1;
|
|
curline = scline_buf[1];
|
|
}
|
|
else
|
|
{
|
|
line_num[0] = base_linep1;
|
|
curline = scline_buf[0];
|
|
}
|
|
|
|
//need to fill
|
|
|
|
SC_hor_filter(ispctx,curline,CrPtr+base_linep1*cro_align_width,src_width,dst_width,hratio,ispctx->SC_chroma_hor_init_phase,0,0);
|
|
}
|
|
|
|
//vertical filter
|
|
C = ispctx->SC_VER_FILTER_COEFF[vphase>>3];
|
|
for(j=0;j<dst_width;j++)
|
|
{
|
|
r = lastline[j]*C[0] + curline[j]*C[1];
|
|
r += 128;
|
|
r >>= 8;
|
|
*dst_ptr++ = CLIP(r,0,255);
|
|
}
|
|
dst_ptr += cro_sub_num;
|
|
}
|
|
|
|
memcpy(pdst,DstBuf,ispctx->outpicsize);
|
|
|
|
free(scline_buf[0]);
|
|
free(DstBuf);
|
|
}
|
|
|
|
// fmt: only support YV12
|
|
int scaler(unsigned char * psrc, unsigned char * pdst, int src_w, int src_h, int dst_w, int dst_h, int fmt, int align)
|
|
{
|
|
int i;
|
|
ISP_CTX isp_ctx,*ispctx;
|
|
ispctx = &isp_ctx;
|
|
ispctx->width = src_w;
|
|
ispctx->height = src_h;
|
|
ispctx->SC_dst_width = dst_w;
|
|
ispctx->SC_dst_height = dst_h;
|
|
ispctx->SC_luma_ver_init_phase = 0;
|
|
ispctx->SC_luma_hor_init_phase = 0;
|
|
ispctx->SC_chroma_hor_init_phase = 0;
|
|
ispctx->SC_chroma_ver_init_phase = 0;
|
|
if(fmt == 0)
|
|
ispctx->outpicsize = dst_w*dst_h*1.5;
|
|
|
|
for(i=0;i<16;i++)
|
|
{
|
|
ispctx->SC_HOR_FILTER_COEFF0[i][0] = cubic_coeff[i*4*2];
|
|
ispctx->SC_HOR_FILTER_COEFF0[i][1] = cubic_coeff[i*4*2+1];
|
|
ispctx->SC_HOR_FILTER_COEFF0[i][2] = cubic_coeff[i*4*2+2];
|
|
ispctx->SC_HOR_FILTER_COEFF0[i][3] = cubic_coeff[i*4*2+3];
|
|
}
|
|
|
|
for(i=0;i<32;i++)
|
|
{
|
|
ispctx->SC_VER_FILTER_COEFF[i][0] = (32-i)<<3;
|
|
ispctx->SC_VER_FILTER_COEFF[i][1] = i<<3;
|
|
}
|
|
|
|
|
|
ispctx->SC_luma_hor_ratio = (src_w*256 + (dst_w/2))/dst_w;
|
|
ispctx->SC_luma_ver_ratio = (src_h*256 + (dst_h/2))/dst_h;
|
|
do_scaler(ispctx,psrc,pdst,src_w,src_h,dst_w,dst_h,fmt,align);
|
|
return 0;
|
|
} |