author: CarlsonLee([email protected]), 本代码是freecamera的一部分,freecamera源代码存在:http://gitorious.org/freecamera
///scale
typedef struct _VSImage
{
guchar *pixels;
int width;
int height;
int stride;
}VSImage;
static void vs_scanline_resample_nearest_Y (guchar * dest, guchar * src, int src_width,
int n, int *accumulator, int increment)
{
int acc = *accumulator;
int i;
int j;
int x;
for (i = 0; i < n; i++) {
j = acc >> 16;
x = acc & 0xffff;
dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
acc += increment;
}
*accumulator = acc;
}
static void vs_scanline_resample_linear_Y (guchar * dest, guchar * src, int src_width,
int n, int *accumulator, int increment)
{
int acc = *accumulator;
int i;
int j;
int x;
for (i = 0; i < n; i++)
{
j = acc >> 16;
x = acc & 0xffff;
if (j + 1 < src_width)
dest[i] = (src[j] * (65536 - x) + src[j + 1] * x) >> 16;
else
dest[i] = src[j];
acc += increment;
}
*accumulator = acc;
}
static void orc_merge_linear_u8 (guchar * d1, const guchar * s1, const guchar * s2,
int p1, int p2, int n)
{
int i;
gchar var0;
gchar *ptr0;
gchar var4;
const gchar *ptr4;
gchar var5;
const gchar *ptr5;
const gshort var16 = 128;
const gshort var17 = 8;
const int var24 = p1;
const int var25 = p2;
gshort var32;
gshort var33;
gshort var34;
gshort var35;
gshort var36;
ptr0 = (gchar *) d1;
ptr4 = (gchar *) s1;
ptr5 = (gchar *) s2;
for (i = 0; i < n; i++)
{
var4 = *ptr4;
ptr4++;
var5 = *ptr5;
ptr5++;
/* 0: mulubw */
var32 = (guchar) var4 *(guchar) var24;
/* 1: mulubw */
var33 = (guchar) var5 *(guchar) var25;
/* 2: addw */
var34 = var32 + var33;
/* 3: addw */
var35 = var34 + var16;
/* 4: shruw */
var36 = ((gushort) var35) >> var17;
/* 5: convwb */
var0 = var36;
*ptr0 = var0;
ptr0++;
}
}
static void vs_scanline_merge_linear_Y (guchar * dest, guchar * src1, guchar * src2, int n, int x)
{
guint value = x >> 8;
if (value == 0)
{
memcpy (dest, src1, n);
}
else
{
orc_merge_linear_u8 (dest, src1, src2, 256 - value, value, n);
}
}
static void vs_image_scale_nearest_Y (const VSImage * dest, const VSImage * src, guchar * tmpbuf)
{
int acc;
int y_increment;
int x_increment;
int i;
int j;
int xacc;
if (dest->height == 1)
y_increment = 0;
else
y_increment = ((src->height - 1) << 16) / (dest->height - 1);
if (dest->width == 1)
x_increment = 0;
else
x_increment = ((src->width - 1) << 16) / (dest->width - 1);
acc = 0;
for (i = 0; i < dest->height; i++)
{
j = acc >> 16;
xacc = 0;
vs_scanline_resample_nearest_Y (dest->pixels + i * dest->stride,
src->pixels + j * src->stride, src->width, dest->width, &xacc,
x_increment);
acc += y_increment;
}
}
static void vs_image_scale_linear_Y (const VSImage * dest, const VSImage * src, guchar * tmpbuf)
{
int acc;
int y_increment;
int x_increment;
guchar *tmp1;
guchar *tmp2;
int y1;
int y2;
int i;
int j;
int x;
int dest_size;
int xacc;
if (dest->height == 1)
y_increment = 0;
else
y_increment = ((src->height - 1) << 16) / (dest->height - 1);
if (dest->width == 1)
x_increment = 0;
else
x_increment = ((src->width - 1) << 16) / (dest->width - 1);
dest_size = dest->width;
tmp1 = tmpbuf;
tmp2 = tmpbuf + dest_size;
acc = 0;
xacc = 0;
y2 = -1;
vs_scanline_resample_linear_Y (tmp1, src->pixels, src->width, dest->width, &xacc, x_increment);
y1 = 0;
for (i = 0; i < dest->height; i++)
{
j = acc >> 16;
x = acc & 0xffff;
if (x == 0)
{
if (j == y1)
{
memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
} else if (j == y2)
{
memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
}
else
{
xacc = 0;
vs_scanline_resample_linear_Y (tmp1, src->pixels + j * src->stride, src->width, dest->width, &xacc, x_increment);
y1 = j;
memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
}
}
else
{
if (j == y1)
{
if (j + 1 != y2)
{
xacc = 0;
vs_scanline_resample_linear_Y (tmp2, src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc, x_increment);
y2 = j + 1;
}
vs_scanline_merge_linear_Y (dest->pixels + i * dest->stride, tmp1, tmp2, dest->width, x);
}
else if (j == y2)
{
if (j + 1 != y1)
{
xacc = 0;
vs_scanline_resample_linear_Y (tmp1,
src->pixels + (j + 1) * src->stride, src->width, dest->width,
&xacc, x_increment);
y1 = j + 1;
}
vs_scanline_merge_linear_Y (dest->pixels + i * dest->stride,
tmp2, tmp1, dest->width, x);
} else {
xacc = 0;
vs_scanline_resample_linear_Y (tmp1, src->pixels + j * src->stride,
src->width, dest->width, &xacc, x_increment);
y1 = j;
xacc = 0;
vs_scanline_resample_linear_Y (tmp2,
src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
x_increment);
y2 = (j + 1);
vs_scanline_merge_linear_Y (dest->pixels + i * dest->stride,
tmp1, tmp2, dest->width, x);
}
}
acc += y_increment;
}
}
void resample_yv12(guchar* dest, gint dest_w, gint dest_h, guchar* src, gint src_w, gint src_h, SCALE_TYPE scale_type)
{
VSImage dest_y;
VSImage dest_u;
VSImage dest_v;
VSImage src_y;
VSImage src_u;
VSImage src_v;
guchar *tmp_buf = malloc(dest_w*4*2);
if(tmp_buf == NULL)
return;
dest_y.pixels = dest;
dest_y.width = dest_w;
dest_y.height = dest_h;
dest_y.stride = dest_w;
dest_u.pixels = dest + dest_w*dest_h;
dest_u.width = dest_w/2;
dest_u.height = dest_h/2;
dest_u.stride = dest_w/2;
dest_v.pixels = dest + dest_w*dest_h*5/4;
dest_v.width = dest_w/2;
dest_v.height = dest_h/2;
dest_v.stride = dest_w/2;
src_y.pixels = src;
src_y.width = src_w;
src_y.height = src_h;
src_y.stride = src_w;
src_u.pixels = src + src_w*src_h;
src_u.width = src_w/2;
src_u.height = src_h/2;
src_u.stride = src_w/2;
src_v.pixels = src + src_w*src_h*5/4;
src_v.width = src_w/2;
src_v.height = src_h/2;
src_v.stride = src_w/2;
if(scale_type == SCALE_TYEP_NEAREST)
{
vs_image_scale_nearest_Y (&dest_y, &src_y, tmp_buf);
vs_image_scale_nearest_Y (&dest_u, &src_u, tmp_buf);
vs_image_scale_nearest_Y (&dest_v, &src_v, tmp_buf);
}
else if(scale_type == SCALE_TYPE_BILINEAR)
{
vs_image_scale_linear_Y (&dest_y, &src_y, tmp_buf);
vs_image_scale_linear_Y (&dest_u, &src_u, tmp_buf);
vs_image_scale_linear_Y (&dest_v, &src_v, tmp_buf);
}
free(tmp_buf);
}