/Avc/yuv420rgb8888c.cpp
C++ | 187 lines | 103 code | 10 blank | 74 comment | 15 complexity | 111c1d66dbb4323ba2eaba9345fc5f62 MD5 | raw file
1/* YUV-> RGB conversion code. 2 * 3 * Copyright (C) 2011 Robin Watts (robin@wss.co.uk) for Pinknoise 4 * Productions Ltd. 5 * 6 * Licensed under the BSD license. See 'COPYING' for details of 7 * (non-)warranty. 8 * 9 * 10 * The algorithm used here is based heavily on one created by Sophie Wilson 11 * of Acorn/e-14/Broadcomm. Many thanks. 12 * 13 * Additional tweaks (in the fast fixup code) are from Paul Gardiner. 14 * 15 * The old implementation of YUV -> RGB did: 16 * 17 * R = CLAMP((Y-16)*1.164 + 1.596*V) 18 * G = CLAMP((Y-16)*1.164 - 0.391*U - 0.813*V) 19 * B = CLAMP((Y-16)*1.164 + 2.018*U ) 20 * 21 * We're going to bend that here as follows: 22 * 23 * R = CLAMP(y + 1.596*V) 24 * G = CLAMP(y - 0.383*U - 0.813*V) 25 * B = CLAMP(y + 1.976*U ) 26 * 27 * where y = 0 for Y <= 16, 28 * y = ( Y-16)*1.164, for 16 < Y <= 239, 29 * y = (239-16)*1.164, for 239 < Y 30 * 31 * i.e. We clamp Y to the 16 to 239 range (which it is supposed to be in 32 * anyway). We then pick the B_U factor so that B never exceeds 511. We then 33 * shrink the G_U factor in line with that to avoid a colour shift as much as 34 * possible. 35 * 36 * We're going to use tables to do it faster, but rather than doing it using 37 * 5 tables as as the above suggests, we're going to do it using just 3. 38 * 39 * We do this by working in parallel within a 32 bit word, and using one 40 * table each for Y U and V. 41 * 42 * Source Y values are 0 to 255, so 0.. 260 after scaling 43 * Source U values are -128 to 127, so -49.. 49(G), -253..251(B) after 44 * Source V values are -128 to 127, so -204..203(R), -104..103(G) after 45 * 46 * So total summed values: 47 * -223 <= R <= 481, -173 <= G <= 431, -253 <= B < 511 48 * 49 * We need to pack R G and B into a 32 bit word, and because of Bs range we 50 * need 2 bits above the valid range of B to detect overflow, and another one 51 * to detect the sense of the overflow. We therefore adopt the following 52 * representation: 53 * 54 * osGGGGGgggggosBBBBBbbbosRRRRRrrr 55 * 56 * Each such word breaks down into 3 ranges. 57 * 58 * osGGGGGggggg osBBBBBbbb osRRRRRrrr 59 * 60 * Thus we have 8 bits for each B and R table entry, and 10 bits for G (good 61 * as G is the most noticable one). The s bit for each represents the sign, 62 * and o represents the overflow. 63 * 64 * For R and B we pack the table by taking the 11 bit representation of their 65 * values, and toggling bit 10 in the U and V tables. 66 * 67 * For the green case we calculate 4*G (thus effectively using 10 bits for the 68 * valid range) truncate to 12 bits. We toggle bit 11 in the Y table. 69 */ 70 71#include "yuv2rgb.h" 72 73enum 74{ 75 FLAGS = 0x40080100 76}; 77 78#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)]) 79#define READY(Y) tables[Y] 80#define FIXUP(Y) \ 81do { \ 82 int tmp = (Y) & FLAGS; \ 83 if (tmp != 0) \ 84 { \ 85 tmp -= tmp>>8; \ 86 (Y) |= tmp; \ 87 tmp = FLAGS & ~(Y>>1); \ 88 (Y) += tmp>>8; \ 89 } \ 90} while (0 == 1) 91 92#define STORE(Y,DSTPTR) \ 93do { \ 94 (DSTPTR) = (Y & 0xFF) | (0xFF00 & (Y>>14)) | (0xFF0000 & (Y<<5)) ;\ 95} while (0 == 1) 96 97void yuv420_2_rgb8888(uint8_t *dst_ptr_, 98 const uint8_t *y_ptr, 99 const uint8_t *u_ptr, 100 const uint8_t *v_ptr, 101 int32_t width, 102 int32_t height, 103 int32_t y_span, 104 int32_t uv_span, 105 int32_t dst_span, 106 const uint32_t *tables, 107 int32_t dither) 108{ 109 uint32_t *dst_ptr = (uint32_t *)(void *)dst_ptr_; 110 dst_span >>= 2; 111 112 height -= 1; 113 while (height > 0) 114 { 115 height -= width<<16; 116 height += 1<<16; 117 while (height < 0) 118 { 119 /* Do 2 column pairs */ 120 uint32_t uv, y0, y1; 121 122 uv = READUV(*u_ptr++,*v_ptr++); 123 y1 = uv + READY(y_ptr[y_span]); 124 y0 = uv + READY(*y_ptr++); 125 FIXUP(y1); 126 FIXUP(y0); 127 STORE(y1, dst_ptr[dst_span]); 128 STORE(y0, *dst_ptr++); 129 y1 = uv + READY(y_ptr[y_span]); 130 y0 = uv + READY(*y_ptr++); 131 FIXUP(y1); 132 FIXUP(y0); 133 STORE(y1, dst_ptr[dst_span]); 134 STORE(y0, *dst_ptr++); 135 height += (2<<16); 136 } 137 if ((height>>16) == 0) 138 { 139 /* Trailing column pair */ 140 uint32_t uv, y0, y1; 141 142 uv = READUV(*u_ptr,*v_ptr); 143 y1 = uv + READY(y_ptr[y_span]); 144 y0 = uv + READY(*y_ptr++); 145 FIXUP(y1); 146 FIXUP(y0); 147 STORE(y0, dst_ptr[dst_span]); 148 STORE(y1, *dst_ptr++); 149 } 150 dst_ptr += dst_span*2-width; 151 y_ptr += y_span*2-width; 152 u_ptr += uv_span-(width>>1); 153 v_ptr += uv_span-(width>>1); 154 height = (height<<16)>>16; 155 height -= 2; 156 } 157 if (height == 0) 158 { 159 /* Trail row */ 160 height -= width<<16; 161 height += 1<<16; 162 while (height < 0) 163 { 164 /* Do a row pair */ 165 uint32_t uv, y0, y1; 166 167 uv = READUV(*u_ptr++,*v_ptr++); 168 y1 = uv + READY(*y_ptr++); 169 y0 = uv + READY(*y_ptr++); 170 FIXUP(y1); 171 FIXUP(y0); 172 STORE(y1, *dst_ptr++); 173 STORE(y0, *dst_ptr++); 174 height += (2<<16); 175 } 176 if ((height>>16) == 0) 177 { 178 /* Trailing pix */ 179 uint32_t uv, y0; 180 181 uv = READUV(*u_ptr++,*v_ptr++); 182 y0 = uv + READY(*y_ptr++); 183 FIXUP(y0); 184 STORE(y0, *dst_ptr++); 185 } 186 } 187}