-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathyuv422rgb8888c.c
182 lines (173 loc) · 5.5 KB
/
yuv422rgb8888c.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* YUV-> RGB conversion code.
*
* Copyright (C) 2011 Robin Watts ([email protected]) for Pinknoise
* Productions Ltd.
*
* Licensed under the BSD license. See 'COPYING' for details of
* (non-)warranty.
*
*
* The algorithm used here is based heavily on one created by Sophie Wilson
* of Acorn/e-14/Broadcomm. Many thanks.
*
* 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 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 { \
*(DSTPTR)++ = (Y); \
*(DSTPTR)++ = (Y)>>22; \
*(DSTPTR)++ = (Y)>>11; \
*(DSTPTR)++ = 0; \
} while (0 == 1)
void yuv422_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)
{
height -= 1;
while (height > 0)
{
height -= width<<16;
height += 1<<16;
while (height < 0)
{
/* Do top row pair */
uint32_t uv, y0, y1;
uv = READUV(*u_ptr++,*v_ptr++);
y0 = uv + READY(*y_ptr++);
y1 = uv + READY(*y_ptr++);
FIXUP(y0);
FIXUP(y1);
STORE(y0, dst_ptr);
STORE(y1, dst_ptr);
height += (2<<16);
}
if ((height>>16) == 0)
{
/* Trailing top row pix */
uint32_t uv, y0;
uv = READUV(*u_ptr,*v_ptr);
y0 = uv + READY(*y_ptr++);
FIXUP(y0);
STORE(y0, dst_ptr);
}
dst_ptr += dst_span-width*4;
y_ptr += y_span-width;
u_ptr += uv_span-(width>>1);
v_ptr += uv_span-(width>>1);
height = (height<<16)>>16;
height -= 1;
if (height == 0)
break;
height -= width<<16;
height += 1<<16;
while (height < 0)
{
/* Do second row pair */
uint32_t uv, y0, y1;
uv = READUV(*u_ptr++,*v_ptr++);
y0 = uv + READY(*y_ptr++);
y1 = uv + READY(*y_ptr++);
FIXUP(y0);
FIXUP(y1);
STORE(y0, dst_ptr);
STORE(y1, dst_ptr);
height += (2<<16);
}
if ((height>>16) == 0)
{
/* Trailing bottom row pix */
uint32_t uv, y0;
uv = READUV(*u_ptr,*v_ptr);
y0 = uv + READY(*y_ptr++);
FIXUP(y0);
STORE(y0, dst_ptr);
}
dst_ptr += dst_span-width*4;
y_ptr += y_span-width;
u_ptr += uv_span-(width>>1);
v_ptr += uv_span-(width>>1);
height = (height<<16)>>16;
height -= 1;
}
}