1 // Copyright 2010 Google Inc.
2 //
3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // -----------------------------------------------------------------------------
7 //
8 // inline YUV->RGB conversion function
9 //
10 // Author: Skal (pascal.massimino@gmail.com)
11
12 #ifndef WEBP_DEC_YUV_H_
13 #define WEBP_DEC_YUV_H_
14
15 #include "webp/decode_vp8.h"
16
17 /*
18 * Define ANDROID_WEBP_RGB to enable specific optimizations for Android
19 * RGBA_4444 & RGB_565 color support.
20 *
21 */
22
23 #define ANDROID_WEBP_RGB
24
25 #if defined(__cplusplus) || defined(c_plusplus)
26 extern "C" {
27 #endif
28
29 enum { YUV_FIX = 16, // fixed-point precision
30 YUV_RANGE_MIN = -227, // min value of r/g/b output
31 YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output
32 };
33 extern int16_t VP8kVToR[256], VP8kUToB[256];
34 extern int32_t VP8kVToG[256], VP8kUToG[256];
35 extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
36 extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
37
VP8YuvToRgb(uint8_t y,uint8_t u,uint8_t v,uint8_t * const rgb)38 static inline void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
39 uint8_t* const rgb) {
40 const int r_off = VP8kVToR[v];
41 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
42 const int b_off = VP8kUToB[u];
43 rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN];
44 rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
45 rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
46 }
47
VP8YuvToRgb565(uint8_t y,uint8_t u,uint8_t v,uint8_t * const rgb)48 static inline void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
49 uint8_t* const rgb) {
50 const int r_off = VP8kVToR[v];
51 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
52 const int b_off = VP8kUToB[u];
53 #ifdef ANDROID_WEBP_RGB
54 rgb[1] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
55 (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
56 rgb[0] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
57 (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
58 #else
59 rgb[0] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
60 (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
61 rgb[1] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
62 (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
63 #endif
64 }
65
VP8YuvToArgbKeepA(uint8_t y,uint8_t u,uint8_t v,uint8_t * const argb)66 static inline void VP8YuvToArgbKeepA(uint8_t y, uint8_t u, uint8_t v,
67 uint8_t* const argb) {
68 // Don't update Aplha (argb[0])
69 VP8YuvToRgb(y, u, v, argb + 1);
70 }
71
VP8YuvToArgb(uint8_t y,uint8_t u,uint8_t v,uint8_t * const argb)72 static inline void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
73 uint8_t* const argb) {
74 argb[0] = 0xff;
75 VP8YuvToArgbKeepA(y, u, v, argb);
76 }
77
VP8YuvToRgba4444KeepA(uint8_t y,uint8_t u,uint8_t v,uint8_t * const argb)78 static inline void VP8YuvToRgba4444KeepA(uint8_t y, uint8_t u, uint8_t v,
79 uint8_t* const argb) {
80 const int r_off = VP8kVToR[v];
81 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
82 const int b_off = VP8kUToB[u];
83 #ifdef ANDROID_WEBP_RGB
84 argb[1] = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
85 VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
86 argb[0] = (argb[0] & 0x0f) | (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4);
87 #else
88 argb[0] = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
89 VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
90 argb[1] = (argb[1] & 0x0f) | (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4);
91 #endif
92 }
93
VP8YuvToRgba4444(uint8_t y,uint8_t u,uint8_t v,uint8_t * const argb)94 static inline void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v,
95 uint8_t* const argb) {
96 #ifdef ANDROID_WEBP_RGB
97 argb[0] = 0x0f;
98 #else
99 argb[1] = 0x0f;
100 #endif
101 VP8YuvToRgba4444KeepA(y, u, v, argb);
102 }
103
VP8YuvToBgr(uint8_t y,uint8_t u,uint8_t v,uint8_t * const bgr)104 static inline void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
105 uint8_t* const bgr) {
106 const int r_off = VP8kVToR[v];
107 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
108 const int b_off = VP8kUToB[u];
109 bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
110 bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
111 bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
112 }
113
VP8YuvToBgra(uint8_t y,uint8_t u,uint8_t v,uint8_t * const bgra)114 static inline void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
115 uint8_t* const bgra) {
116 VP8YuvToBgr(y, u, v, bgra);
117 bgra[3] = 0xff;
118 }
119
VP8YuvToRgba(uint8_t y,uint8_t u,uint8_t v,uint8_t * const rgba)120 static inline void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
121 uint8_t* const rgba) {
122 VP8YuvToRgb(y, u, v, rgba);
123 rgba[3] = 0xff;
124 }
125
126 // Must be called before everything, to initialize the tables.
127 void VP8YUVInit(void);
128
129 #if defined(__cplusplus) || defined(c_plusplus)
130 } // extern "C"
131 #endif
132
133 #endif // WEBP_DEC_YUV_H_
134