opencv/android/android-opencv/jni/yuv420sp2rgb.c
2011-04-06 14:31:03 +00:00

157 lines
3.4 KiB
C

#include <string.h>
#include <jni.h>
#include <yuv420sp2rgb.h>
#include <yuv2rgb.h>
/*
YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved
U/V plane containing 8 bit 2x2 subsampled chroma samples.
except the interleave order of U and V is reversed.
H V
Y Sample Period 1 1
U (Cb) Sample Period 2 2
V (Cr) Sample Period 2 2
*/
/*
size of a char:
find . -name limits.h -exec grep CHAR_BIT {} \;
*/
#ifndef max
#define max(a,b) (a > b ? a : b )
#define min(a,b) (a < b ? a : b )
#endif
enum
{
FLAGS = 0x40080100
};
#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
#define READY(Y) tables[Y]
#define FIXUP(Y) \
do { \
int tmp = (Y) & FLAGS; \
if (tmp != 0) \
{ \
tmp -= tmp>>8; \
(Y) |= tmp; \
tmp = FLAGS & ~(Y>>1); \
(Y) += tmp>>8; \
} \
} while (0 == 1)
#define STORE(Y,DSTPTR) \
do { \
uint32_t Y2 = (Y); \
uint8_t *DSTPTR2 = (DSTPTR); \
(DSTPTR2)[2] = (Y2); \
(DSTPTR2)[1] = (Y2)>>22; \
(DSTPTR2)[0] = (Y2)>>11; \
} while (0 == 1)
typedef unsigned char byte;
const int bytes_per_pixel = 2;
void color_convert_common(const unsigned char *pY, const unsigned char *pUV, int width, int height,
unsigned char *buffer, int grey)
{
#define LOOKUP 1
#if ! LOOKUP
int nR, nG, nB;
#endif
int dest_span = 3 * width;
unsigned char *out = buffer;
if (grey)
{
memcpy(out, pY, width * height * sizeof(unsigned char));
}
else
{
#if LOOKUP
const uint32_t* tables = yuv2rgb565_table;
const byte* nY = pY;
const byte* nUV = pUV;
int idx = 0;
while (nY+width < pUV)
{
int y = (idx / width);
int x = (idx % width);
byte Y = *nY;
byte Y2 = nY[width];
byte V = *nUV;
byte U = *(nUV + 1);
/* Do 2 row pairs */
uint32_t uv, y0, y1;
uv = READUV(U,V);
y1 = uv + READY(Y);
y0 = uv + READY(Y2);
FIXUP(y1);
FIXUP(y0);
STORE(y1, &out[dest_span]);
STORE(y0, out);
out += 3;
Y = *(++nY);
Y2 = nY[width];
y1 = uv + READY(Y);
y0 = uv + READY(Y2);
FIXUP(y1);
FIXUP(y0);
STORE(y1, &out[dest_span]);
STORE(y0, out);
out += 3;
height += (2 << 16);
++nY;
nUV = pUV + (y / 2) * width + 2 * (x / 2);
idx+=2;
}
#else
const byte* nY = pY;
const byte* nUV = pUV;
int idx = 0;
while (nY < pUV)
{
int y = (idx / width);
int x = (idx % width);
int Y = *nY;
int V = *nUV;
int U = *(nUV + 1);
Y -= 16;
V -= 128;
U -= 128;
if (y < 0)
y = 0;
nB = (int)(1192 * Y + 2066 * U);
nG = (int)(1192 * Y - 833 * V - 400 * U);
nR = (int)(1192 * Y + 1634 * V);
nR = min(262143, max(0, nR));
nG = min(262143, max(0, nG));
nB = min(262143, max(0, nB));
nR >>= 10;
nR &= 0xff;
nG >>= 10;
nG &= 0xff;
nB >>= 10;
nB &= 0xff;
*(out++) = (unsigned char)nR;
*(out++) = (unsigned char)nG;
*(out++) = (unsigned char)nB;
nY += 1;
nUV = pUV + (y / 2) * width + 2 * (x / 2);
++idx;
}
#endif
}
}