PageRenderTime 171ms CodeModel.GetById 163ms app.highlight 6ms RepoModel.GetById 0ms app.codeStats 0ms

/Avc/yuv420rgb888c.cpp

http://github.com/mbebenita/Broadway
C++ | 194 lines | 111 code | 9 blank | 74 comment | 15 complexity | 286c551db5d5abf5a4e155e44325560b 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    uint32_t Y2       = (Y);      \
 95    uint8_t  *DSTPTR2 = (DSTPTR); \
 96    (DSTPTR2)[0] = (Y2);          \
 97    (DSTPTR2)[1] = (Y2)>>22;      \
 98    (DSTPTR2)[2] = (Y2)>>11;      \
 99} while (0 == 1)
100
101void yuv420_2_rgb888(uint8_t  *dst_ptr,
102               const uint8_t  *y_ptr,
103               const uint8_t  *u_ptr,
104               const uint8_t  *v_ptr,
105                     int32_t   width,
106                     int32_t   height,
107                     int32_t   y_span,
108                     int32_t   uv_span,
109                     int32_t   dst_span,
110               const uint32_t *tables,
111                     int32_t   dither)
112{
113    height -= 1;
114    while (height > 0)
115    {
116        height -= width<<16;
117        height += 1<<16;
118        while (height < 0)
119        {
120            /* Do 2 column pairs */
121            uint32_t uv, y0, y1;
122
123            uv  = READUV(*u_ptr++,*v_ptr++);
124            y1  = uv + READY(y_ptr[y_span]);
125            y0  = uv + READY(*y_ptr++);
126            FIXUP(y1);
127            FIXUP(y0);
128            STORE(y1, &dst_ptr[dst_span]);
129            STORE(y0, dst_ptr);
130            dst_ptr += 3;
131            y1  = uv + READY(y_ptr[y_span]);
132            y0  = uv + READY(*y_ptr++);
133            FIXUP(y1);
134            FIXUP(y0);
135            STORE(y1, &dst_ptr[dst_span]);
136            STORE(y0, dst_ptr);
137            dst_ptr += 3;
138            height += (2<<16);
139        }
140        if ((height>>16) == 0)
141        {
142            /* Trailing column pair */
143            uint32_t uv, y0, y1;
144
145            uv = READUV(*u_ptr,*v_ptr);
146            y1 = uv + READY(y_ptr[y_span]);
147            y0 = uv + READY(*y_ptr++);
148            FIXUP(y1);
149            FIXUP(y0);
150            STORE(y0, &dst_ptr[dst_span]);
151            STORE(y1, dst_ptr);
152            dst_ptr += 3;
153        }
154        dst_ptr += dst_span*2-width*3;
155        y_ptr   += y_span*2-width;
156        u_ptr   += uv_span-(width>>1);
157        v_ptr   += uv_span-(width>>1);
158        height = (height<<16)>>16;
159        height -= 2;
160    }
161    if (height == 0)
162    {
163        /* Trail row */
164        height -= width<<16;
165        height += 1<<16;
166        while (height < 0)
167        {
168            /* Do a row pair */
169            uint32_t uv, y0, y1;
170
171            uv  = READUV(*u_ptr++,*v_ptr++);
172            y1  = uv + READY(*y_ptr++);
173            y0  = uv + READY(*y_ptr++);
174            FIXUP(y1);
175            FIXUP(y0);
176            STORE(y1, dst_ptr);
177            dst_ptr += 3;
178            STORE(y0, dst_ptr);
179            dst_ptr += 3;
180            height += (2<<16);
181        }
182        if ((height>>16) == 0)
183        {
184            /* Trailing pix */
185            uint32_t uv, y0;
186
187            uv = READUV(*u_ptr++,*v_ptr++);
188            y0 = uv + READY(*y_ptr++);
189            FIXUP(y0);
190            STORE(y0, dst_ptr);
191            dst_ptr += 3;
192        }
193    }
194}