Revision 25db8dbb49a887fd523060338112637cb7ac1cd2 authored by Giovanni Condello on 27 March 2014, 10:32:59 UTC, committed by Giovanni Condello on 27 March 2014, 10:32:59 UTC
1 parent bd1d1b8
imgconv.c
#include "dryos.h"
#include "imgconv.h"
#include "bmp.h"
// precompute some parts of YUV to RGB computations
int yuv2rgb_RV[256];
int yuv2rgb_GU[256];
int yuv2rgb_GV[256];
int yuv2rgb_BU[256];
/** http://www.martinreddy.net/gfx/faqs/colorconv.faq
* BT 601:
* R'= Y' + 0.000*U' + 1.403*V'
* G'= Y' - 0.344*U' - 0.714*V'
* B'= Y' + 1.773*U' + 0.000*V'
*
* BT 709:
* R'= Y' + 0.0000*Cb + 1.5701*Cr
* G'= Y' - 0.1870*Cb - 0.4664*Cr
* B'= Y' - 1.8556*Cb + 0.0000*Cr
*/
void precompute_yuv2rgb()
{
#ifdef CONFIG_REC709
/*
*R = *Y + 1608 * V / 1024;
*G = *Y - 191 * U / 1024 - 478 * V / 1024;
*B = *Y + 1900 * U / 1024;
*/
for (int u = 0; u < 256; u++)
{
int8_t U = u;
yuv2rgb_GU[u] = (-191 * U) >> 10;
yuv2rgb_BU[u] = (1900 * U) >> 10;
}
for (int v = 0; v < 256; v++)
{
int8_t V = v;
yuv2rgb_RV[v] = (1608 * V) >> 10;
yuv2rgb_GV[v] = (-478 * V) >> 10;
}
#else // REC 601
/*
*R = *Y + ((1437 * V) >> 10);
*G = *Y - ((352 * U) >> 10) - ((731 * V) >> 10);
*B = *Y + ((1812 * U) >> 10);
*/
for (int u = 0; u < 256; u++)
{
int8_t U = u;
yuv2rgb_GU[u] = (-352 * U) >> 10;
yuv2rgb_BU[u] = (1812 * U) >> 10;
}
for (int v = 0; v < 256; v++)
{
int8_t V = v;
yuv2rgb_RV[v] = (1437 * V) >> 10;
yuv2rgb_GV[v] = (-731 * V) >> 10;
}
#endif
}
/*inline void uyvy2yrgb(uint32_t uyvy, int* Y, int* R, int* G, int* B)
{
uint32_t y1 = (uyvy >> 24) & 0xFF;
uint32_t y2 = (uyvy >> 8) & 0xFF;
*Y = (y1+y2) / 2;
uint8_t u = (uyvy >> 0) & 0xFF;
uint8_t v = (uyvy >> 16) & 0xFF;
*R = MIN(*Y + yuv2rgb_RV[v], 255);
*G = MIN(*Y + yuv2rgb_GU[u] + yuv2rgb_GV[v], 255);
*B = MIN(*Y + yuv2rgb_BU[u], 255);
} */
void yuv2rgb(int Y, int U, int V, int* R, int* G, int* B)
{
const int v_and_ff = V & 0xFF;
const int u_and_ff = U & 0xFF;
int v = Y + yuv2rgb_RV[v_and_ff];
*R = COERCE(v, 0, 255);
v = Y + yuv2rgb_GU[u_and_ff] + yuv2rgb_GV[v_and_ff];
*G = COERCE(v, 0, 255);
v = Y + yuv2rgb_BU[u_and_ff];
*B = COERCE(v, 0, 255);
}
/**
* BT.709:
* Y'= 0.2126*R' + 0.7152*G' + 0.0722*B'
* Cb=-0.1146*R' - 0.3854*G' + 0.5000*B'
* Cr= 0.5000*R' - 0.4541*G' - 0.0458*B'
*
* BT.601:
* Y'= 0.2990*R' + 0.5870*G' + 0.1140*B'
* Cb=-0.2990*R' - 0.5870*G' + 0.8860*B'
* Cr= 0.7010*R' - 0.5870*G' - 0.1140*B'
*
* see:
* http://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-5-200204-I!!PDF-E.pdf
* http://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.601-7-201103-I!!PDF-E.pdf
*/
uint32_t rgb2yuv422_rec709(int R, int G, int B)
{
int Y = COERCE(((217) * R + (732) * G + (73) * B) / 1024, 0, 255);
int U = COERCE(((-117) * R + (-394) * G + (512) * B) / 1024, -128, 127);
int V = COERCE(((512) * R + (-465) * G + (-46) * B) / 1024, -128, 127);
return UYVY_PACK(U,Y,V,Y);
}
uint32_t rgb2yuv422_rec601(int R, int G, int B)
{
int Y = COERCE(((306) * R + (601) * G + (116) * B) / 1024, 0, 255);
int U = COERCE(((-172) * R + (-337) * G + (509) * B) / 1024, -128, 127);
int V = COERCE(((509) * R + (-427) * G + (-82) * B) / 1024, -128, 127);
return UYVY_PACK(U,Y,V,Y);
}
uint32_t rgb2yuv422(int R, int G, int B)
{
#if defined(CONFIG_REC709)
return rgb2yuv422_rec709(R, G, B);
#else
return rgb2yuv422_rec601(R, G, B);
#endif
}
void uyvy_split(uint32_t uyvy, int* Y, int* U, int* V)
{
*Y = UYVY_GET_AVG_Y(uyvy);
*U = (int)(int8_t)UYVY_GET_U(uyvy);
*V = (int)(int8_t)UYVY_GET_V(uyvy);
}
void yuv_resize(uint32_t* src, int src_w, int src_h, uint32_t* dst, int dst_w, int dst_h)
{
int i,j;
const int srcw_half = src_w >> 1;
const int dstw_half = dst_w >> 1;
for (i = 0; i < dst_h; i++)
{
const int src_off_part = (i*src_h/dst_h) * srcw_half;
const int dst_off_y = i * dstw_half;
int mult_srcw = 0;
for (j = 0; j < dstw_half; j++, mult_srcw += src_w)
{
dst[dst_off_y + j] = src[src_off_part + mult_srcw/dst_w];
}
}
}
void yuv_halfcopy(uint32_t* dst, uint32_t* src, int w, int h, int top_half)
{
int i,j;
const int w_half = w >> 1;
int pos = 0;
for (i = 0; i < h; i++,pos += w_half)
{
for (j = 0; j < w/2; j++)
{
int sign = j - i * w_half/h;
const int offset = pos + j;
if ((top_half && sign > 0) || (!top_half && sign <= 0))
{
dst[offset] = src[offset];
}
}
}
}
int yuv411_to_422(uint32_t addr)
{
// 4 6 8 A 0 2
// uYvY yYuY vYyY
addr = ALIGN32(addr);
// multiples of 12, offset 0: vYyY u
// multiples of 12, offset 4: uYvY
// multiples of 12, offset 8: yYuY v
uint8_t* p = (uint8_t*) addr;
switch ((addr/4) % 3)
{
case 0:
{
unsigned u = p[4];
unsigned v = p[0];
unsigned y1 = p[1];
unsigned y2 = p[2];
return UYVY_PACK(u,y1,v,y2);
}
case 1:
{
return MEM(addr);
}
case 2:
{
unsigned u = p[2];
unsigned v = p[4];
unsigned y1 = p[0];
unsigned y2 = p[1];
return UYVY_PACK(u,y1,v,y2);
}
}
return 0; // unreachable, shut the compiler warnings
}
void yuv411_to_rgb(uint32_t addr, int* Y, int* R, int* G, int* B)
{
// 4 6 8 A 0 2
// uYvY yYuY vYyY
addr = addr & ~3; // multiple of 4
// multiples of 12, offset 0: vYyY u
// multiples of 12, offset 4: uYvY
// multiples of 12, offset 8: yYuY v
uint8_t* p = (uint8_t*) addr;
int y = 0;
int U = 0;
int V = 0;
// trick to compute [ am3 = (addr/4) % 3 ] a little bit faster
static int am3 = 0;
static unsigned int prev_addr = 0;
if (likely(addr == prev_addr + 4))
{
am3 = am3 + 1;
if (unlikely(am3 == 3)) am3 = 0;
}
else if (likely(addr == prev_addr))
{
}
else
{
am3 = (addr/4) % 3;
}
prev_addr = addr;
switch (am3)
{
case 0:
U = p[4];
V = p[0];
y = p[1];
break;
case 1:
U = p[0];
V = p[2];
y = p[1];
break;
case 2:
U = p[2];
V = p[4];
y = p[0];
break;
}
*Y = y;
*R = COERCE(y + yuv2rgb_RV[V], 0, 255);
*G = COERCE(y + yuv2rgb_GU[U] + yuv2rgb_GV[V], 0, 255);
*B = COERCE(y + yuv2rgb_BU[U], 0, 255);
}
static void FAST yuvcpy_x2(uint32_t* dst, uint32_t* src, int num_pix)
{
dst = ALIGN32(dst);
src = ALIGN32(src);
uint32_t* last_s = src + (num_pix>>1);
for (; src < last_s; src++, dst += 2)
{
uint32_t chroma = (*src) & 0x00FF00FF;
uint32_t luma1 = (*src >> 8) & 0xFF;
uint32_t luma2 = (*src >> 24) & 0xFF;
*(dst) = chroma | (luma1 << 8) | (luma1 << 24);
*(dst+1) = chroma | (luma2 << 8) | (luma2 << 24);
}
}
static void FAST yuvcpy_x3(uint32_t* dst, uint32_t* src, int num_pix)
{
dst = ALIGN32(dst);
src = ALIGN32(src);
uint32_t* last_s = src + (num_pix>>1);
for (; src < last_s; src++, dst += 3)
{
uint32_t chroma = (*src) & 0x00FF00FF;
uint32_t luma1 = (*src >> 8) & 0xFF;
uint32_t luma2 = (*src >> 24) & 0xFF;
const int l18 = luma1 << 8;
const int l28 = luma2 << 8;
const int l224 = luma2 << 24;
*(dst) = chroma | l18 | (luma1 << 24);
*(dst+1) = chroma | l18 | l224;
*(dst+2) = chroma | l28 | l224;
}
}
void yuvcpy_main(uint32_t* dst, uint32_t* src, int num_pix, int X)
{
dst = ALIGN32(dst);
src = ALIGN32(src);
if (X==1)
{
#ifdef CONFIG_DMA_MEMCPY
dma_memcpy(dst, src, num_pix << 1);
#else
memcpy(dst, src, num_pix << 1);
#endif
}
else if (X==2)
{
yuvcpy_x2(dst, src, num_pix >> 1);
}
else if (X==3)
{
yuvcpy_x3(dst, src, num_pix/3);
}
}
void little_cleanup(void* BP, void* MP)
{
uint8_t* bp = BP; uint8_t* mp = MP;
if (*bp != 0 && *bp == *mp) *mp = *bp = 0;
bp++; mp++;
if (*bp != 0 && *bp == *mp) *mp = *bp = 0;
bp++; mp++;
if (*bp != 0 && *bp == *mp) *mp = *bp = 0;
bp++; mp++;
if (*bp != 0 && *bp == *mp) *mp = *bp = 0;
}
uint32_t yuv422_get_pixel(uint32_t* buf, int pixoff)
{
uint32_t* src = &buf[pixoff / 2];
uint32_t chroma = (*src) & 0x00FF00FF;
uint32_t luma1 = (*src >> 8) & 0xFF;
uint32_t luma2 = (*src >> 24) & 0xFF;
uint32_t luma = pixoff % 2 ? luma2 : luma1;
return (chroma | (luma << 8) | (luma << 24));
}
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...