#### /Avc/yuv420rgb8888c.cpp

C++ | 187 lines | 103 code | 10 blank | 74 comment | 15 complexity | 111c1d66dbb4323ba2eaba9345fc5f62 MD5 | raw file
``````
/* YUV-> RGB conversion code.
*
* Copyright (C) 2011 Robin Watts (robin@wss.co.uk) for Pinknoise
* Productions Ltd.
*
* (non-)warranty.
*
*
* The algorithm used here is based heavily on one created by Sophie Wilson
*
* Additional tweaks (in the fast fixup code) are from Paul Gardiner.
*
* The old implementation of YUV -> RGB did:
*
* R = CLAMP((Y-16)*1.164 +           1.596*V)
* G = CLAMP((Y-16)*1.164 - 0.391*U - 0.813*V)
* B = CLAMP((Y-16)*1.164 + 2.018*U          )
*
* We're going to bend that here as follows:
*
* R = CLAMP(y +           1.596*V)
* G = CLAMP(y - 0.383*U - 0.813*V)
* B = CLAMP(y + 1.976*U          )
*
* where y = 0               for       Y <=  16,
*       y = (  Y-16)*1.164, for  16 < Y <= 239,
*       y = (239-16)*1.164, for 239 < Y
*
* i.e. We clamp Y to the 16 to 239 range (which it is supposed to be in
* anyway). We then pick the B_U factor so that B never exceeds 511. We then
* shrink the G_U factor in line with that to avoid a colour shift as much as
* possible.
*
* We're going to use tables to do it faster, but rather than doing it using
* 5 tables as as the above suggests, we're going to do it using just 3.
*
* We do this by working in parallel within a 32 bit word, and using one
* table each for Y U and V.
*
* Source Y values are    0 to 255, so    0.. 260 after scaling
* Source U values are -128 to 127, so  -49.. 49(G), -253..251(B) after
* Source V values are -128 to 127, so -204..203(R), -104..103(G) after
*
* So total summed values:
* -223 <= R <= 481, -173 <= G <= 431, -253 <= B < 511
*
* We need to pack R G and B into a 32 bit word, and because of Bs range we
* need 2 bits above the valid range of B to detect overflow, and another one
* to detect the sense of the overflow. We therefore adopt the following
* representation:
*
* osGGGGGgggggosBBBBBbbbosRRRRRrrr
*
* Each such word breaks down into 3 ranges.
*
* osGGGGGggggg   osBBBBBbbb   osRRRRRrrr
*
* Thus we have 8 bits for each B and R table entry, and 10 bits for G (good
* as G is the most noticable one). The s bit for each represents the sign,
* and o represents the overflow.
*
* For R and B we pack the table by taking the 11 bit representation of their
* values, and toggling bit 10 in the U and V tables.
*
* For the green case we calculate 4*G (thus effectively using 10 bits for the
* valid range) truncate to 12 bits. We toggle bit 11 in the Y table.
*/

#include "yuv2rgb.h"

enum
{
FLAGS         = 0x40080100
};

#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
#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 {                        \
(DSTPTR) = (Y & 0xFF) | (0xFF00 & (Y>>14)) | (0xFF0000 & (Y<<5)) ;\
} while (0 == 1)

void yuv420_2_rgb8888(uint8_t  *dst_ptr_,
const uint8_t  *y_ptr,
const uint8_t  *u_ptr,
const uint8_t  *v_ptr,
int32_t   width,
int32_t   height,
int32_t   y_span,
int32_t   uv_span,
int32_t   dst_span,
const uint32_t *tables,
int32_t   dither)
{
uint32_t *dst_ptr = (uint32_t *)(void *)dst_ptr_;
dst_span >>= 2;

height -= 1;
while (height > 0)
{
height -= width<<16;
height += 1<<16;
while (height < 0)
{
/* Do 2 column pairs */
uint32_t uv, y0, y1;

FIXUP(y1);
FIXUP(y0);
STORE(y1, dst_ptr[dst_span]);
STORE(y0, *dst_ptr++);
FIXUP(y1);
FIXUP(y0);
STORE(y1, dst_ptr[dst_span]);
STORE(y0, *dst_ptr++);
height += (2<<16);
}
if ((height>>16) == 0)
{
/* Trailing column pair */
uint32_t uv, y0, y1;

FIXUP(y1);
FIXUP(y0);
STORE(y0, dst_ptr[dst_span]);
STORE(y1, *dst_ptr++);
}
dst_ptr += dst_span*2-width;
y_ptr   += y_span*2-width;
u_ptr   += uv_span-(width>>1);
v_ptr   += uv_span-(width>>1);
height = (height<<16)>>16;
height -= 2;
}
if (height == 0)
{
/* Trail row */
height -= width<<16;
height += 1<<16;
while (height < 0)
{
/* Do a row pair */
uint32_t uv, y0, y1;

FIXUP(y1);
FIXUP(y0);
STORE(y1, *dst_ptr++);
STORE(y0, *dst_ptr++);
height += (2<<16);
}
if ((height>>16) == 0)
{
/* Trailing pix */
uint32_t uv, y0;