1 // Copyright 2012 Google Inc. All Rights Reserved.
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 // Image transforms and color space conversion methods for lossless decoder.
9 //
10 // Authors: Vikas Arora (vikaas.arora@gmail.com)
11 // Jyrki Alakuijala (jyrki@google.com)
12 // Urvang Joshi (urvang@google.com)
13
14 #define ANDROID_WEBP_RGB
15
16 #if defined(__cplusplus) || defined(c_plusplus)
17 extern "C" {
18 #endif
19
20 #include <math.h>
21 #include <stdlib.h>
22 #include "./lossless.h"
23 #include "../dec/vp8li.h"
24 #include "../dsp/yuv.h"
25 #include "../dsp/dsp.h"
26 #include "../enc/histogram.h"
27
28 #define MAX_DIFF_COST (1e30f)
29
30 // lookup table for small values of log2(int)
31 #define APPROX_LOG_MAX 4096
32 #define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
33 #define LOG_LOOKUP_IDX_MAX 256
34 static const float kLog2Table[LOG_LOOKUP_IDX_MAX] = {
35 0.0000000000000000f, 0.0000000000000000f,
36 1.0000000000000000f, 1.5849625007211560f,
37 2.0000000000000000f, 2.3219280948873621f,
38 2.5849625007211560f, 2.8073549220576041f,
39 3.0000000000000000f, 3.1699250014423121f,
40 3.3219280948873621f, 3.4594316186372973f,
41 3.5849625007211560f, 3.7004397181410921f,
42 3.8073549220576041f, 3.9068905956085187f,
43 4.0000000000000000f, 4.0874628412503390f,
44 4.1699250014423121f, 4.2479275134435852f,
45 4.3219280948873626f, 4.3923174227787606f,
46 4.4594316186372973f, 4.5235619560570130f,
47 4.5849625007211560f, 4.6438561897747243f,
48 4.7004397181410917f, 4.7548875021634682f,
49 4.8073549220576037f, 4.8579809951275718f,
50 4.9068905956085187f, 4.9541963103868749f,
51 5.0000000000000000f, 5.0443941193584533f,
52 5.0874628412503390f, 5.1292830169449663f,
53 5.1699250014423121f, 5.2094533656289501f,
54 5.2479275134435852f, 5.2854022188622487f,
55 5.3219280948873626f, 5.3575520046180837f,
56 5.3923174227787606f, 5.4262647547020979f,
57 5.4594316186372973f, 5.4918530963296747f,
58 5.5235619560570130f, 5.5545888516776376f,
59 5.5849625007211560f, 5.6147098441152083f,
60 5.6438561897747243f, 5.6724253419714951f,
61 5.7004397181410917f, 5.7279204545631987f,
62 5.7548875021634682f, 5.7813597135246599f,
63 5.8073549220576037f, 5.8328900141647412f,
64 5.8579809951275718f, 5.8826430493618415f,
65 5.9068905956085187f, 5.9307373375628866f,
66 5.9541963103868749f, 5.9772799234999167f,
67 6.0000000000000000f, 6.0223678130284543f,
68 6.0443941193584533f, 6.0660891904577720f,
69 6.0874628412503390f, 6.1085244567781691f,
70 6.1292830169449663f, 6.1497471195046822f,
71 6.1699250014423121f, 6.1898245588800175f,
72 6.2094533656289501f, 6.2288186904958804f,
73 6.2479275134435852f, 6.2667865406949010f,
74 6.2854022188622487f, 6.3037807481771030f,
75 6.3219280948873626f, 6.3398500028846243f,
76 6.3575520046180837f, 6.3750394313469245f,
77 6.3923174227787606f, 6.4093909361377017f,
78 6.4262647547020979f, 6.4429434958487279f,
79 6.4594316186372973f, 6.4757334309663976f,
80 6.4918530963296747f, 6.5077946401986963f,
81 6.5235619560570130f, 6.5391588111080309f,
82 6.5545888516776376f, 6.5698556083309478f,
83 6.5849625007211560f, 6.5999128421871278f,
84 6.6147098441152083f, 6.6293566200796094f,
85 6.6438561897747243f, 6.6582114827517946f,
86 6.6724253419714951f, 6.6865005271832185f,
87 6.7004397181410917f, 6.7142455176661224f,
88 6.7279204545631987f, 6.7414669864011464f,
89 6.7548875021634682f, 6.7681843247769259f,
90 6.7813597135246599f, 6.7944158663501061f,
91 6.8073549220576037f, 6.8201789624151878f,
92 6.8328900141647412f, 6.8454900509443747f,
93 6.8579809951275718f, 6.8703647195834047f,
94 6.8826430493618415f, 6.8948177633079437f,
95 6.9068905956085187f, 6.9188632372745946f,
96 6.9307373375628866f, 6.9425145053392398f,
97 6.9541963103868749f, 6.9657842846620869f,
98 6.9772799234999167f, 6.9886846867721654f,
99 7.0000000000000000f, 7.0112272554232539f,
100 7.0223678130284543f, 7.0334230015374501f,
101 7.0443941193584533f, 7.0552824355011898f,
102 7.0660891904577720f, 7.0768155970508308f,
103 7.0874628412503390f, 7.0980320829605263f,
104 7.1085244567781691f, 7.1189410727235076f,
105 7.1292830169449663f, 7.1395513523987936f,
106 7.1497471195046822f, 7.1598713367783890f,
107 7.1699250014423121f, 7.1799090900149344f,
108 7.1898245588800175f, 7.1996723448363644f,
109 7.2094533656289501f, 7.2191685204621611f,
110 7.2288186904958804f, 7.2384047393250785f,
111 7.2479275134435852f, 7.2573878426926521f,
112 7.2667865406949010f, 7.2761244052742375f,
113 7.2854022188622487f, 7.2946207488916270f,
114 7.3037807481771030f, 7.3128829552843557f,
115 7.3219280948873626f, 7.3309168781146167f,
116 7.3398500028846243f, 7.3487281542310771f,
117 7.3575520046180837f, 7.3663222142458160f,
118 7.3750394313469245f, 7.3837042924740519f,
119 7.3923174227787606f, 7.4008794362821843f,
120 7.4093909361377017f, 7.4178525148858982f,
121 7.4262647547020979f, 7.4346282276367245f,
122 7.4429434958487279f, 7.4512111118323289f,
123 7.4594316186372973f, 7.4676055500829976f,
124 7.4757334309663976f, 7.4838157772642563f,
125 7.4918530963296747f, 7.4998458870832056f,
126 7.5077946401986963f, 7.5156998382840427f,
127 7.5235619560570130f, 7.5313814605163118f,
128 7.5391588111080309f, 7.5468944598876364f,
129 7.5545888516776376f, 7.5622424242210728f,
130 7.5698556083309478f, 7.5774288280357486f,
131 7.5849625007211560f, 7.5924570372680806f,
132 7.5999128421871278f, 7.6073303137496104f,
133 7.6147098441152083f, 7.6220518194563764f,
134 7.6293566200796094f, 7.6366246205436487f,
135 7.6438561897747243f, 7.6510516911789281f,
136 7.6582114827517946f, 7.6653359171851764f,
137 7.6724253419714951f, 7.6794800995054464f,
138 7.6865005271832185f, 7.6934869574993252f,
139 7.7004397181410917f, 7.7073591320808825f,
140 7.7142455176661224f, 7.7210991887071855f,
141 7.7279204545631987f, 7.7347096202258383f,
142 7.7414669864011464f, 7.7481928495894605f,
143 7.7548875021634682f, 7.7615512324444795f,
144 7.7681843247769259f, 7.7747870596011736f,
145 7.7813597135246599f, 7.7879025593914317f,
146 7.7944158663501061f, 7.8008998999203047f,
147 7.8073549220576037f, 7.8137811912170374f,
148 7.8201789624151878f, 7.8265484872909150f,
149 7.8328900141647412f, 7.8392037880969436f,
150 7.8454900509443747f, 7.8517490414160571f,
151 7.8579809951275718f, 7.8641861446542797f,
152 7.8703647195834047f, 7.8765169465649993f,
153 7.8826430493618415f, 7.8887432488982591f,
154 7.8948177633079437f, 7.9008668079807486f,
155 7.9068905956085187f, 7.9128893362299619f,
156 7.9188632372745946f, 7.9248125036057812f,
157 7.9307373375628866f, 7.9366379390025709f,
158 7.9425145053392398f, 7.9483672315846778f,
159 7.9541963103868749f, 7.9600019320680805f,
160 7.9657842846620869f, 7.9715435539507719f,
161 7.9772799234999167f, 7.9829935746943103f,
162 7.9886846867721654f, 7.9943534368588577f
163 };
164
VP8LFastLog2(int v)165 float VP8LFastLog2(int v) {
166 if (v < LOG_LOOKUP_IDX_MAX) {
167 return kLog2Table[v];
168 } else if (v < APPROX_LOG_MAX) {
169 int log_cnt = 0;
170 while (v >= LOG_LOOKUP_IDX_MAX) {
171 ++log_cnt;
172 v = v >> 1;
173 }
174 return kLog2Table[v] + (float)log_cnt;
175 } else {
176 return (float)(LOG_2_RECIPROCAL * log((double)v));
177 }
178 }
179
180 //------------------------------------------------------------------------------
181 // Image transforms.
182
183 // In-place sum of each component with mod 256.
AddPixelsEq(uint32_t * a,uint32_t b)184 static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) {
185 const uint32_t alpha_and_green = (*a & 0xff00ff00u) + (b & 0xff00ff00u);
186 const uint32_t red_and_blue = (*a & 0x00ff00ffu) + (b & 0x00ff00ffu);
187 *a = (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu);
188 }
189
Average2(uint32_t a0,uint32_t a1)190 static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
191 return (((a0 ^ a1) & 0xfefefefeL) >> 1) + (a0 & a1);
192 }
193
Average3(uint32_t a0,uint32_t a1,uint32_t a2)194 static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
195 return Average2(Average2(a0, a2), a1);
196 }
197
Average4(uint32_t a0,uint32_t a1,uint32_t a2,uint32_t a3)198 static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
199 uint32_t a2, uint32_t a3) {
200 return Average2(Average2(a0, a1), Average2(a2, a3));
201 }
202
Clip255(uint32_t a)203 static WEBP_INLINE uint32_t Clip255(uint32_t a) {
204 if (a < 256) {
205 return a;
206 }
207 // return 0, when a is a negative integer.
208 // return 255, when a is positive.
209 return ~a >> 24;
210 }
211
AddSubtractComponentFull(int a,int b,int c)212 static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) {
213 return Clip255(a + b - c);
214 }
215
ClampedAddSubtractFull(uint32_t c0,uint32_t c1,uint32_t c2)216 static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
217 uint32_t c2) {
218 const int a = AddSubtractComponentFull(c0 >> 24, c1 >> 24, c2 >> 24);
219 const int r = AddSubtractComponentFull((c0 >> 16) & 0xff,
220 (c1 >> 16) & 0xff,
221 (c2 >> 16) & 0xff);
222 const int g = AddSubtractComponentFull((c0 >> 8) & 0xff,
223 (c1 >> 8) & 0xff,
224 (c2 >> 8) & 0xff);
225 const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff);
226 return (a << 24) | (r << 16) | (g << 8) | b;
227 }
228
AddSubtractComponentHalf(int a,int b)229 static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) {
230 return Clip255(a + (a - b) / 2);
231 }
232
ClampedAddSubtractHalf(uint32_t c0,uint32_t c1,uint32_t c2)233 static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
234 uint32_t c2) {
235 const uint32_t ave = Average2(c0, c1);
236 const int a = AddSubtractComponentHalf(ave >> 24, c2 >> 24);
237 const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff);
238 const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff);
239 const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff);
240 return (a << 24) | (r << 16) | (g << 8) | b;
241 }
242
Sub3(int a,int b,int c)243 static WEBP_INLINE int Sub3(int a, int b, int c) {
244 const int pa = b - c;
245 const int pb = a - c;
246 return abs(pa) - abs(pb);
247 }
248
Select(uint32_t a,uint32_t b,uint32_t c)249 static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
250 const int pa_minus_pb =
251 Sub3((a >> 24) , (b >> 24) , (c >> 24) ) +
252 Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) +
253 Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) +
254 Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff);
255
256 return (pa_minus_pb <= 0) ? a : b;
257 }
258
259 //------------------------------------------------------------------------------
260 // Predictors
261
Predictor0(uint32_t left,const uint32_t * const top)262 static uint32_t Predictor0(uint32_t left, const uint32_t* const top) {
263 (void)top;
264 (void)left;
265 return ARGB_BLACK;
266 }
Predictor1(uint32_t left,const uint32_t * const top)267 static uint32_t Predictor1(uint32_t left, const uint32_t* const top) {
268 (void)top;
269 return left;
270 }
Predictor2(uint32_t left,const uint32_t * const top)271 static uint32_t Predictor2(uint32_t left, const uint32_t* const top) {
272 (void)left;
273 return top[0];
274 }
Predictor3(uint32_t left,const uint32_t * const top)275 static uint32_t Predictor3(uint32_t left, const uint32_t* const top) {
276 (void)left;
277 return top[1];
278 }
Predictor4(uint32_t left,const uint32_t * const top)279 static uint32_t Predictor4(uint32_t left, const uint32_t* const top) {
280 (void)left;
281 return top[-1];
282 }
Predictor5(uint32_t left,const uint32_t * const top)283 static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
284 const uint32_t pred = Average3(left, top[0], top[1]);
285 return pred;
286 }
Predictor6(uint32_t left,const uint32_t * const top)287 static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
288 const uint32_t pred = Average2(left, top[-1]);
289 return pred;
290 }
Predictor7(uint32_t left,const uint32_t * const top)291 static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
292 const uint32_t pred = Average2(left, top[0]);
293 return pred;
294 }
Predictor8(uint32_t left,const uint32_t * const top)295 static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
296 const uint32_t pred = Average2(top[-1], top[0]);
297 (void)left;
298 return pred;
299 }
Predictor9(uint32_t left,const uint32_t * const top)300 static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
301 const uint32_t pred = Average2(top[0], top[1]);
302 (void)left;
303 return pred;
304 }
Predictor10(uint32_t left,const uint32_t * const top)305 static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
306 const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
307 return pred;
308 }
Predictor11(uint32_t left,const uint32_t * const top)309 static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
310 const uint32_t pred = Select(top[0], left, top[-1]);
311 return pred;
312 }
Predictor12(uint32_t left,const uint32_t * const top)313 static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
314 const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
315 return pred;
316 }
Predictor13(uint32_t left,const uint32_t * const top)317 static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
318 const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
319 return pred;
320 }
321
322 typedef uint32_t (*PredictorFunc)(uint32_t left, const uint32_t* const top);
323 static const PredictorFunc kPredictors[16] = {
324 Predictor0, Predictor1, Predictor2, Predictor3,
325 Predictor4, Predictor5, Predictor6, Predictor7,
326 Predictor8, Predictor9, Predictor10, Predictor11,
327 Predictor12, Predictor13,
328 Predictor0, Predictor0 // <- padding security sentinels
329 };
330
331 // TODO(vikasa): Replace 256 etc with defines.
PredictionCostSpatial(const int * counts,int weight_0,double exp_val)332 static float PredictionCostSpatial(const int* counts,
333 int weight_0, double exp_val) {
334 const int significant_symbols = 16;
335 const double exp_decay_factor = 0.6;
336 double bits = weight_0 * counts[0];
337 int i;
338 for (i = 1; i < significant_symbols; ++i) {
339 bits += exp_val * (counts[i] + counts[256 - i]);
340 exp_val *= exp_decay_factor;
341 }
342 return (float)(-0.1 * bits);
343 }
344
345 // Compute the Shanon's entropy: Sum(p*log2(p))
ShannonEntropy(const int * const array,int n)346 static float ShannonEntropy(const int* const array, int n) {
347 int i;
348 float retval = 0.f;
349 int sum = 0;
350 for (i = 0; i < n; ++i) {
351 if (array[i] != 0) {
352 sum += array[i];
353 retval -= VP8LFastSLog2(array[i]);
354 }
355 }
356 retval += VP8LFastSLog2(sum);
357 return retval;
358 }
359
PredictionCostSpatialHistogram(int accumulated[4][256],int tile[4][256])360 static float PredictionCostSpatialHistogram(int accumulated[4][256],
361 int tile[4][256]) {
362 int i;
363 int k;
364 int combo[256];
365 double retval = 0;
366 for (i = 0; i < 4; ++i) {
367 const double exp_val = 0.94;
368 retval += PredictionCostSpatial(&tile[i][0], 1, exp_val);
369 retval += ShannonEntropy(&tile[i][0], 256);
370 for (k = 0; k < 256; ++k) {
371 combo[k] = accumulated[i][k] + tile[i][k];
372 }
373 retval += ShannonEntropy(&combo[0], 256);
374 }
375 return (float)retval;
376 }
377
GetBestPredictorForTile(int width,int height,int tile_x,int tile_y,int bits,int accumulated[4][256],const uint32_t * const argb_scratch)378 static int GetBestPredictorForTile(int width, int height,
379 int tile_x, int tile_y, int bits,
380 int accumulated[4][256],
381 const uint32_t* const argb_scratch) {
382 const int kNumPredModes = 14;
383 const int col_start = tile_x << bits;
384 const int row_start = tile_y << bits;
385 const int tile_size = 1 << bits;
386 const int ymax = (tile_size <= height - row_start) ?
387 tile_size : height - row_start;
388 const int xmax = (tile_size <= width - col_start) ?
389 tile_size : width - col_start;
390 int histo[4][256];
391 float best_diff = MAX_DIFF_COST;
392 int best_mode = 0;
393
394 int mode;
395 for (mode = 0; mode < kNumPredModes; ++mode) {
396 const uint32_t* current_row = argb_scratch;
397 const PredictorFunc pred_func = kPredictors[mode];
398 float cur_diff;
399 int y;
400 memset(&histo[0][0], 0, sizeof(histo));
401 for (y = 0; y < ymax; ++y) {
402 int x;
403 const int row = row_start + y;
404 const uint32_t* const upper_row = current_row;
405 current_row = upper_row + width;
406 for (x = 0; x < xmax; ++x) {
407 const int col = col_start + x;
408 uint32_t predict;
409 uint32_t predict_diff;
410 if (row == 0) {
411 predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
412 } else if (col == 0) {
413 predict = upper_row[col]; // Top.
414 } else {
415 predict = pred_func(current_row[col - 1], upper_row + col);
416 }
417 predict_diff = VP8LSubPixels(current_row[col], predict);
418 ++histo[0][predict_diff >> 24];
419 ++histo[1][((predict_diff >> 16) & 0xff)];
420 ++histo[2][((predict_diff >> 8) & 0xff)];
421 ++histo[3][(predict_diff & 0xff)];
422 }
423 }
424 cur_diff = PredictionCostSpatialHistogram(accumulated, histo);
425 if (cur_diff < best_diff) {
426 best_diff = cur_diff;
427 best_mode = mode;
428 }
429 }
430
431 return best_mode;
432 }
433
CopyTileWithPrediction(int width,int height,int tile_x,int tile_y,int bits,int mode,const uint32_t * const argb_scratch,uint32_t * const argb)434 static void CopyTileWithPrediction(int width, int height,
435 int tile_x, int tile_y, int bits, int mode,
436 const uint32_t* const argb_scratch,
437 uint32_t* const argb) {
438 const int col_start = tile_x << bits;
439 const int row_start = tile_y << bits;
440 const int tile_size = 1 << bits;
441 const int ymax = (tile_size <= height - row_start) ?
442 tile_size : height - row_start;
443 const int xmax = (tile_size <= width - col_start) ?
444 tile_size : width - col_start;
445 const PredictorFunc pred_func = kPredictors[mode];
446 const uint32_t* current_row = argb_scratch;
447
448 int y;
449 for (y = 0; y < ymax; ++y) {
450 int x;
451 const int row = row_start + y;
452 const uint32_t* const upper_row = current_row;
453 current_row = upper_row + width;
454 for (x = 0; x < xmax; ++x) {
455 const int col = col_start + x;
456 const int pix = row * width + col;
457 uint32_t predict;
458 if (row == 0) {
459 predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
460 } else if (col == 0) {
461 predict = upper_row[col]; // Top.
462 } else {
463 predict = pred_func(current_row[col - 1], upper_row + col);
464 }
465 argb[pix] = VP8LSubPixels(current_row[col], predict);
466 }
467 }
468 }
469
VP8LResidualImage(int width,int height,int bits,uint32_t * const argb,uint32_t * const argb_scratch,uint32_t * const image)470 void VP8LResidualImage(int width, int height, int bits,
471 uint32_t* const argb, uint32_t* const argb_scratch,
472 uint32_t* const image) {
473 const int max_tile_size = 1 << bits;
474 const int tiles_per_row = VP8LSubSampleSize(width, bits);
475 const int tiles_per_col = VP8LSubSampleSize(height, bits);
476 uint32_t* const upper_row = argb_scratch;
477 uint32_t* const current_tile_rows = argb_scratch + width;
478 int tile_y;
479 int histo[4][256];
480 memset(histo, 0, sizeof(histo));
481 for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
482 const int tile_y_offset = tile_y * max_tile_size;
483 const int this_tile_height =
484 (tile_y < tiles_per_col - 1) ? max_tile_size : height - tile_y_offset;
485 int tile_x;
486 if (tile_y > 0) {
487 memcpy(upper_row, current_tile_rows + (max_tile_size - 1) * width,
488 width * sizeof(*upper_row));
489 }
490 memcpy(current_tile_rows, &argb[tile_y_offset * width],
491 this_tile_height * width * sizeof(*current_tile_rows));
492 for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
493 int pred;
494 int y;
495 const int tile_x_offset = tile_x * max_tile_size;
496 int all_x_max = tile_x_offset + max_tile_size;
497 if (all_x_max > width) {
498 all_x_max = width;
499 }
500 pred = GetBestPredictorForTile(width, height, tile_x, tile_y, bits, histo,
501 argb_scratch);
502 image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
503 CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred,
504 argb_scratch, argb);
505 for (y = 0; y < max_tile_size; ++y) {
506 int ix;
507 int all_x;
508 int all_y = tile_y_offset + y;
509 if (all_y >= height) {
510 break;
511 }
512 ix = all_y * width + tile_x_offset;
513 for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
514 const uint32_t a = argb[ix];
515 ++histo[0][a >> 24];
516 ++histo[1][((a >> 16) & 0xff)];
517 ++histo[2][((a >> 8) & 0xff)];
518 ++histo[3][(a & 0xff)];
519 }
520 }
521 }
522 }
523 }
524
525 // Inverse prediction.
PredictorInverseTransform(const VP8LTransform * const transform,int y_start,int y_end,uint32_t * data)526 static void PredictorInverseTransform(const VP8LTransform* const transform,
527 int y_start, int y_end, uint32_t* data) {
528 const int width = transform->xsize_;
529 if (y_start == 0) { // First Row follows the L (mode=1) mode.
530 int x;
531 const uint32_t pred0 = Predictor0(data[-1], NULL);
532 AddPixelsEq(data, pred0);
533 for (x = 1; x < width; ++x) {
534 const uint32_t pred1 = Predictor1(data[x - 1], NULL);
535 AddPixelsEq(data + x, pred1);
536 }
537 data += width;
538 ++y_start;
539 }
540
541 {
542 int y = y_start;
543 const int mask = (1 << transform->bits_) - 1;
544 const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
545 const uint32_t* pred_mode_base =
546 transform->data_ + (y >> transform->bits_) * tiles_per_row;
547
548 while (y < y_end) {
549 int x;
550 const uint32_t pred2 = Predictor2(data[-1], data - width);
551 const uint32_t* pred_mode_src = pred_mode_base;
552 PredictorFunc pred_func;
553
554 // First pixel follows the T (mode=2) mode.
555 AddPixelsEq(data, pred2);
556
557 // .. the rest:
558 pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
559 for (x = 1; x < width; ++x) {
560 uint32_t pred;
561 if ((x & mask) == 0) { // start of tile. Read predictor function.
562 pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
563 }
564 pred = pred_func(data[x - 1], data + x - width);
565 AddPixelsEq(data + x, pred);
566 }
567 data += width;
568 ++y;
569 if ((y & mask) == 0) { // Use the same mask, since tiles are squares.
570 pred_mode_base += tiles_per_row;
571 }
572 }
573 }
574 }
575
VP8LSubtractGreenFromBlueAndRed(uint32_t * argb_data,int num_pixs)576 void VP8LSubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs) {
577 int i;
578 for (i = 0; i < num_pixs; ++i) {
579 const uint32_t argb = argb_data[i];
580 const uint32_t green = (argb >> 8) & 0xff;
581 const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff;
582 const uint32_t new_b = ((argb & 0xff) - green) & 0xff;
583 argb_data[i] = (argb & 0xff00ff00) | (new_r << 16) | new_b;
584 }
585 }
586
587 // Add green to blue and red channels (i.e. perform the inverse transform of
588 // 'subtract green').
AddGreenToBlueAndRed(const VP8LTransform * const transform,int y_start,int y_end,uint32_t * data)589 static void AddGreenToBlueAndRed(const VP8LTransform* const transform,
590 int y_start, int y_end, uint32_t* data) {
591 const int width = transform->xsize_;
592 const uint32_t* const data_end = data + (y_end - y_start) * width;
593 while (data < data_end) {
594 const uint32_t argb = *data;
595 // "* 0001001u" is equivalent to "(green << 16) + green)"
596 const uint32_t green = ((argb >> 8) & 0xff);
597 uint32_t red_blue = (argb & 0x00ff00ffu);
598 red_blue += (green << 16) | green;
599 red_blue &= 0x00ff00ffu;
600 *data++ = (argb & 0xff00ff00u) | red_blue;
601 }
602 }
603
604 typedef struct {
605 // Note: the members are uint8_t, so that any negative values are
606 // automatically converted to "mod 256" values.
607 uint8_t green_to_red_;
608 uint8_t green_to_blue_;
609 uint8_t red_to_blue_;
610 } Multipliers;
611
MultipliersClear(Multipliers * m)612 static WEBP_INLINE void MultipliersClear(Multipliers* m) {
613 m->green_to_red_ = 0;
614 m->green_to_blue_ = 0;
615 m->red_to_blue_ = 0;
616 }
617
ColorTransformDelta(int8_t color_pred,int8_t color)618 static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred,
619 int8_t color) {
620 return (uint32_t)((int)(color_pred) * color) >> 5;
621 }
622
ColorCodeToMultipliers(uint32_t color_code,Multipliers * const m)623 static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code,
624 Multipliers* const m) {
625 m->green_to_red_ = (color_code >> 0) & 0xff;
626 m->green_to_blue_ = (color_code >> 8) & 0xff;
627 m->red_to_blue_ = (color_code >> 16) & 0xff;
628 }
629
MultipliersToColorCode(Multipliers * const m)630 static WEBP_INLINE uint32_t MultipliersToColorCode(Multipliers* const m) {
631 return 0xff000000u |
632 ((uint32_t)(m->red_to_blue_) << 16) |
633 ((uint32_t)(m->green_to_blue_) << 8) |
634 m->green_to_red_;
635 }
636
TransformColor(const Multipliers * const m,uint32_t argb,int inverse)637 static WEBP_INLINE uint32_t TransformColor(const Multipliers* const m,
638 uint32_t argb, int inverse) {
639 const uint32_t green = argb >> 8;
640 const uint32_t red = argb >> 16;
641 uint32_t new_red = red;
642 uint32_t new_blue = argb;
643
644 if (inverse) {
645 new_red += ColorTransformDelta(m->green_to_red_, green);
646 new_red &= 0xff;
647 new_blue += ColorTransformDelta(m->green_to_blue_, green);
648 new_blue += ColorTransformDelta(m->red_to_blue_, new_red);
649 new_blue &= 0xff;
650 } else {
651 new_red -= ColorTransformDelta(m->green_to_red_, green);
652 new_red &= 0xff;
653 new_blue -= ColorTransformDelta(m->green_to_blue_, green);
654 new_blue -= ColorTransformDelta(m->red_to_blue_, red);
655 new_blue &= 0xff;
656 }
657 return (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
658 }
659
SkipRepeatedPixels(const uint32_t * const argb,int ix,int xsize)660 static WEBP_INLINE int SkipRepeatedPixels(const uint32_t* const argb,
661 int ix, int xsize) {
662 const uint32_t v = argb[ix];
663 if (ix >= xsize + 3) {
664 if (v == argb[ix - xsize] &&
665 argb[ix - 1] == argb[ix - xsize - 1] &&
666 argb[ix - 2] == argb[ix - xsize - 2] &&
667 argb[ix - 3] == argb[ix - xsize - 3]) {
668 return 1;
669 }
670 return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1];
671 } else if (ix >= 3) {
672 return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1];
673 }
674 return 0;
675 }
676
PredictionCostCrossColor(const int accumulated[256],const int counts[256])677 static float PredictionCostCrossColor(const int accumulated[256],
678 const int counts[256]) {
679 // Favor low entropy, locally and globally.
680 int i;
681 int combo[256];
682 for (i = 0; i < 256; ++i) {
683 combo[i] = accumulated[i] + counts[i];
684 }
685 return ShannonEntropy(combo, 256) +
686 ShannonEntropy(counts, 256) +
687 PredictionCostSpatial(counts, 3, 2.4); // Favor small absolute values.
688 }
689
GetBestColorTransformForTile(int tile_x,int tile_y,int bits,Multipliers prevX,Multipliers prevY,int step,int xsize,int ysize,int * accumulated_red_histo,int * accumulated_blue_histo,const uint32_t * const argb)690 static Multipliers GetBestColorTransformForTile(
691 int tile_x, int tile_y, int bits,
692 Multipliers prevX,
693 Multipliers prevY,
694 int step, int xsize, int ysize,
695 int* accumulated_red_histo,
696 int* accumulated_blue_histo,
697 const uint32_t* const argb) {
698 float best_diff = MAX_DIFF_COST;
699 float cur_diff;
700 const int halfstep = step / 2;
701 const int max_tile_size = 1 << bits;
702 const int tile_y_offset = tile_y * max_tile_size;
703 const int tile_x_offset = tile_x * max_tile_size;
704 int green_to_red;
705 int green_to_blue;
706 int red_to_blue;
707 int all_x_max = tile_x_offset + max_tile_size;
708 int all_y_max = tile_y_offset + max_tile_size;
709 Multipliers best_tx;
710 MultipliersClear(&best_tx);
711 if (all_x_max > xsize) {
712 all_x_max = xsize;
713 }
714 if (all_y_max > ysize) {
715 all_y_max = ysize;
716 }
717 for (green_to_red = -64; green_to_red <= 64; green_to_red += halfstep) {
718 int histo[256] = { 0 };
719 int all_y;
720 Multipliers tx;
721 MultipliersClear(&tx);
722 tx.green_to_red_ = green_to_red & 0xff;
723
724 for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
725 uint32_t predict;
726 int ix = all_y * xsize + tile_x_offset;
727 int all_x;
728 for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
729 if (SkipRepeatedPixels(argb, ix, xsize)) {
730 continue;
731 }
732 predict = TransformColor(&tx, argb[ix], 0);
733 ++histo[(predict >> 16) & 0xff]; // red.
734 }
735 }
736 cur_diff = PredictionCostCrossColor(&accumulated_red_histo[0], &histo[0]);
737 if (tx.green_to_red_ == prevX.green_to_red_) {
738 cur_diff -= 3; // favor keeping the areas locally similar
739 }
740 if (tx.green_to_red_ == prevY.green_to_red_) {
741 cur_diff -= 3; // favor keeping the areas locally similar
742 }
743 if (tx.green_to_red_ == 0) {
744 cur_diff -= 3;
745 }
746 if (cur_diff < best_diff) {
747 best_diff = cur_diff;
748 best_tx = tx;
749 }
750 }
751 best_diff = MAX_DIFF_COST;
752 green_to_red = best_tx.green_to_red_;
753 for (green_to_blue = -32; green_to_blue <= 32; green_to_blue += step) {
754 for (red_to_blue = -32; red_to_blue <= 32; red_to_blue += step) {
755 int all_y;
756 int histo[256] = { 0 };
757 Multipliers tx;
758 tx.green_to_red_ = green_to_red;
759 tx.green_to_blue_ = green_to_blue;
760 tx.red_to_blue_ = red_to_blue;
761 for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
762 uint32_t predict;
763 int all_x;
764 int ix = all_y * xsize + tile_x_offset;
765 for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
766 if (SkipRepeatedPixels(argb, ix, xsize)) {
767 continue;
768 }
769 predict = TransformColor(&tx, argb[ix], 0);
770 ++histo[predict & 0xff]; // blue.
771 }
772 }
773 cur_diff =
774 PredictionCostCrossColor(&accumulated_blue_histo[0], &histo[0]);
775 if (tx.green_to_blue_ == prevX.green_to_blue_) {
776 cur_diff -= 3; // favor keeping the areas locally similar
777 }
778 if (tx.green_to_blue_ == prevY.green_to_blue_) {
779 cur_diff -= 3; // favor keeping the areas locally similar
780 }
781 if (tx.red_to_blue_ == prevX.red_to_blue_) {
782 cur_diff -= 3; // favor keeping the areas locally similar
783 }
784 if (tx.red_to_blue_ == prevY.red_to_blue_) {
785 cur_diff -= 3; // favor keeping the areas locally similar
786 }
787 if (tx.green_to_blue_ == 0) {
788 cur_diff -= 3;
789 }
790 if (tx.red_to_blue_ == 0) {
791 cur_diff -= 3;
792 }
793 if (cur_diff < best_diff) {
794 best_diff = cur_diff;
795 best_tx = tx;
796 }
797 }
798 }
799 return best_tx;
800 }
801
CopyTileWithColorTransform(int xsize,int ysize,int tile_x,int tile_y,int bits,Multipliers color_transform,uint32_t * const argb)802 static void CopyTileWithColorTransform(int xsize, int ysize,
803 int tile_x, int tile_y, int bits,
804 Multipliers color_transform,
805 uint32_t* const argb) {
806 int y;
807 int xscan = 1 << bits;
808 int yscan = 1 << bits;
809 tile_x <<= bits;
810 tile_y <<= bits;
811 if (xscan > xsize - tile_x) {
812 xscan = xsize - tile_x;
813 }
814 if (yscan > ysize - tile_y) {
815 yscan = ysize - tile_y;
816 }
817 yscan += tile_y;
818 for (y = tile_y; y < yscan; ++y) {
819 int ix = y * xsize + tile_x;
820 const int end_ix = ix + xscan;
821 for (; ix < end_ix; ++ix) {
822 argb[ix] = TransformColor(&color_transform, argb[ix], 0);
823 }
824 }
825 }
826
VP8LColorSpaceTransform(int width,int height,int bits,int step,uint32_t * const argb,uint32_t * image)827 void VP8LColorSpaceTransform(int width, int height, int bits, int step,
828 uint32_t* const argb, uint32_t* image) {
829 const int max_tile_size = 1 << bits;
830 int tile_xsize = VP8LSubSampleSize(width, bits);
831 int tile_ysize = VP8LSubSampleSize(height, bits);
832 int accumulated_red_histo[256] = { 0 };
833 int accumulated_blue_histo[256] = { 0 };
834 int tile_y;
835 int tile_x;
836 Multipliers prevX;
837 Multipliers prevY;
838 MultipliersClear(&prevY);
839 MultipliersClear(&prevX);
840 for (tile_y = 0; tile_y < tile_ysize; ++tile_y) {
841 for (tile_x = 0; tile_x < tile_xsize; ++tile_x) {
842 Multipliers color_transform;
843 int all_x_max;
844 int y;
845 const int tile_y_offset = tile_y * max_tile_size;
846 const int tile_x_offset = tile_x * max_tile_size;
847 if (tile_y != 0) {
848 ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX);
849 ColorCodeToMultipliers(image[(tile_y - 1) * tile_xsize + tile_x],
850 &prevY);
851 } else if (tile_x != 0) {
852 ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX);
853 }
854 color_transform =
855 GetBestColorTransformForTile(tile_x, tile_y, bits,
856 prevX, prevY,
857 step, width, height,
858 &accumulated_red_histo[0],
859 &accumulated_blue_histo[0],
860 argb);
861 image[tile_y * tile_xsize + tile_x] =
862 MultipliersToColorCode(&color_transform);
863 CopyTileWithColorTransform(width, height, tile_x, tile_y, bits,
864 color_transform, argb);
865
866 // Gather accumulated histogram data.
867 all_x_max = tile_x_offset + max_tile_size;
868 if (all_x_max > width) {
869 all_x_max = width;
870 }
871 for (y = 0; y < max_tile_size; ++y) {
872 int ix;
873 int all_x;
874 int all_y = tile_y_offset + y;
875 if (all_y >= height) {
876 break;
877 }
878 ix = all_y * width + tile_x_offset;
879 for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
880 if (ix >= 2 &&
881 argb[ix] == argb[ix - 2] &&
882 argb[ix] == argb[ix - 1]) {
883 continue; // repeated pixels are handled by backward references
884 }
885 if (ix >= width + 2 &&
886 argb[ix - 2] == argb[ix - width - 2] &&
887 argb[ix - 1] == argb[ix - width - 1] &&
888 argb[ix] == argb[ix - width]) {
889 continue; // repeated pixels are handled by backward references
890 }
891 ++accumulated_red_histo[(argb[ix] >> 16) & 0xff];
892 ++accumulated_blue_histo[argb[ix] & 0xff];
893 }
894 }
895 }
896 }
897 }
898
899 // Color space inverse transform.
ColorSpaceInverseTransform(const VP8LTransform * const transform,int y_start,int y_end,uint32_t * data)900 static void ColorSpaceInverseTransform(const VP8LTransform* const transform,
901 int y_start, int y_end, uint32_t* data) {
902 const int width = transform->xsize_;
903 const int mask = (1 << transform->bits_) - 1;
904 const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
905 int y = y_start;
906 const uint32_t* pred_row =
907 transform->data_ + (y >> transform->bits_) * tiles_per_row;
908
909 while (y < y_end) {
910 const uint32_t* pred = pred_row;
911 Multipliers m = { 0, 0, 0 };
912 int x;
913
914 for (x = 0; x < width; ++x) {
915 if ((x & mask) == 0) ColorCodeToMultipliers(*pred++, &m);
916 data[x] = TransformColor(&m, data[x], 1);
917 }
918 data += width;
919 ++y;
920 if ((y & mask) == 0) pred_row += tiles_per_row;;
921 }
922 }
923
924 // Separate out pixels packed together using pixel-bundling.
ColorIndexInverseTransform(const VP8LTransform * const transform,int y_start,int y_end,const uint32_t * src,uint32_t * dst)925 static void ColorIndexInverseTransform(
926 const VP8LTransform* const transform,
927 int y_start, int y_end, const uint32_t* src, uint32_t* dst) {
928 int y;
929 const int bits_per_pixel = 8 >> transform->bits_;
930 const int width = transform->xsize_;
931 const uint32_t* const color_map = transform->data_;
932 if (bits_per_pixel < 8) {
933 const int pixels_per_byte = 1 << transform->bits_;
934 const int count_mask = pixels_per_byte - 1;
935 const uint32_t bit_mask = (1 << bits_per_pixel) - 1;
936 for (y = y_start; y < y_end; ++y) {
937 uint32_t packed_pixels = 0;
938 int x;
939 for (x = 0; x < width; ++x) {
940 // We need to load fresh 'packed_pixels' once every 'pixels_per_byte'
941 // increments of x. Fortunately, pixels_per_byte is a power of 2, so
942 // can just use a mask for that, instead of decrementing a counter.
943 if ((x & count_mask) == 0) packed_pixels = ((*src++) >> 8) & 0xff;
944 *dst++ = color_map[packed_pixels & bit_mask];
945 packed_pixels >>= bits_per_pixel;
946 }
947 }
948 } else {
949 for (y = y_start; y < y_end; ++y) {
950 int x;
951 for (x = 0; x < width; ++x) {
952 *dst++ = color_map[((*src++) >> 8) & 0xff];
953 }
954 }
955 }
956 }
957
VP8LInverseTransform(const VP8LTransform * const transform,int row_start,int row_end,const uint32_t * const in,uint32_t * const out)958 void VP8LInverseTransform(const VP8LTransform* const transform,
959 int row_start, int row_end,
960 const uint32_t* const in, uint32_t* const out) {
961 assert(row_start < row_end);
962 assert(row_end <= transform->ysize_);
963 switch (transform->type_) {
964 case SUBTRACT_GREEN:
965 AddGreenToBlueAndRed(transform, row_start, row_end, out);
966 break;
967 case PREDICTOR_TRANSFORM:
968 PredictorInverseTransform(transform, row_start, row_end, out);
969 if (row_end != transform->ysize_) {
970 // The last predicted row in this iteration will be the top-pred row
971 // for the first row in next iteration.
972 const int width = transform->xsize_;
973 memcpy(out - width, out + (row_end - row_start - 1) * width,
974 width * sizeof(*out));
975 }
976 break;
977 case CROSS_COLOR_TRANSFORM:
978 ColorSpaceInverseTransform(transform, row_start, row_end, out);
979 break;
980 case COLOR_INDEXING_TRANSFORM:
981 if (in == out && transform->bits_ > 0) {
982 // Move packed pixels to the end of unpacked region, so that unpacking
983 // can occur seamlessly.
984 // Also, note that this is the only transform that applies on
985 // the effective width of VP8LSubSampleSize(xsize_, bits_). All other
986 // transforms work on effective width of xsize_.
987 const int out_stride = (row_end - row_start) * transform->xsize_;
988 const int in_stride = (row_end - row_start) *
989 VP8LSubSampleSize(transform->xsize_, transform->bits_);
990 uint32_t* const src = out + out_stride - in_stride;
991 memmove(src, out, in_stride * sizeof(*src));
992 ColorIndexInverseTransform(transform, row_start, row_end, src, out);
993 } else {
994 ColorIndexInverseTransform(transform, row_start, row_end, in, out);
995 }
996 break;
997 }
998 }
999
1000 //------------------------------------------------------------------------------
1001 // Color space conversion.
1002
is_big_endian(void)1003 static int is_big_endian(void) {
1004 static const union {
1005 uint16_t w;
1006 uint8_t b[2];
1007 } tmp = { 1 };
1008 return (tmp.b[0] != 1);
1009 }
1010
ConvertBGRAToRGB(const uint32_t * src,int num_pixels,uint8_t * dst)1011 static void ConvertBGRAToRGB(const uint32_t* src,
1012 int num_pixels, uint8_t* dst) {
1013 const uint32_t* const src_end = src + num_pixels;
1014 while (src < src_end) {
1015 const uint32_t argb = *src++;
1016 *dst++ = (argb >> 16) & 0xff;
1017 *dst++ = (argb >> 8) & 0xff;
1018 *dst++ = (argb >> 0) & 0xff;
1019 }
1020 }
1021
ConvertBGRAToRGBA(const uint32_t * src,int num_pixels,uint8_t * dst)1022 static void ConvertBGRAToRGBA(const uint32_t* src,
1023 int num_pixels, uint8_t* dst) {
1024 const uint32_t* const src_end = src + num_pixels;
1025 while (src < src_end) {
1026 const uint32_t argb = *src++;
1027 *dst++ = (argb >> 16) & 0xff;
1028 *dst++ = (argb >> 8) & 0xff;
1029 *dst++ = (argb >> 0) & 0xff;
1030 *dst++ = (argb >> 24) & 0xff;
1031 }
1032 }
1033
ConvertBGRAToRGBA4444(const uint32_t * src,int num_pixels,uint8_t * dst)1034 static void ConvertBGRAToRGBA4444(const uint32_t* src,
1035 int num_pixels, uint8_t* dst) {
1036 const uint32_t* const src_end = src + num_pixels;
1037 while (src < src_end) {
1038 const uint32_t argb = *src++;
1039 #ifdef ANDROID_WEBP_RGB
1040 *dst++ = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);
1041 *dst++ = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);
1042 #else
1043 *dst++ = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);
1044 *dst++ = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);
1045 #endif
1046 }
1047 }
1048
ConvertBGRAToRGB565(const uint32_t * src,int num_pixels,uint8_t * dst)1049 static void ConvertBGRAToRGB565(const uint32_t* src,
1050 int num_pixels, uint8_t* dst) {
1051 const uint32_t* const src_end = src + num_pixels;
1052 while (src < src_end) {
1053 const uint32_t argb = *src++;
1054 #ifdef ANDROID_WEBP_RGB
1055 *dst++ = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);
1056 *dst++ = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);
1057 #else
1058 *dst++ = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);
1059 *dst++ = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);
1060 #endif
1061 }
1062 }
1063
ConvertBGRAToBGR(const uint32_t * src,int num_pixels,uint8_t * dst)1064 static void ConvertBGRAToBGR(const uint32_t* src,
1065 int num_pixels, uint8_t* dst) {
1066 const uint32_t* const src_end = src + num_pixels;
1067 while (src < src_end) {
1068 const uint32_t argb = *src++;
1069 *dst++ = (argb >> 0) & 0xff;
1070 *dst++ = (argb >> 8) & 0xff;
1071 *dst++ = (argb >> 16) & 0xff;
1072 }
1073 }
1074
CopyOrSwap(const uint32_t * src,int num_pixels,uint8_t * dst,int swap_on_big_endian)1075 static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst,
1076 int swap_on_big_endian) {
1077 if (is_big_endian() == swap_on_big_endian) {
1078 const uint32_t* const src_end = src + num_pixels;
1079 while (src < src_end) {
1080 uint32_t argb = *src++;
1081 #if !defined(__BIG_ENDIAN__) && (defined(__i386__) || defined(__x86_64__))
1082 __asm__ volatile("bswap %0" : "=r"(argb) : "0"(argb));
1083 *(uint32_t*)dst = argb;
1084 dst += sizeof(argb);
1085 #elif !defined(__BIG_ENDIAN__) && defined(_MSC_VER)
1086 argb = _byteswap_ulong(argb);
1087 *(uint32_t*)dst = argb;
1088 dst += sizeof(argb);
1089 #else
1090 *dst++ = (argb >> 24) & 0xff;
1091 *dst++ = (argb >> 16) & 0xff;
1092 *dst++ = (argb >> 8) & 0xff;
1093 *dst++ = (argb >> 0) & 0xff;
1094 #endif
1095 }
1096 } else {
1097 memcpy(dst, src, num_pixels * sizeof(*src));
1098 }
1099 }
1100
VP8LConvertFromBGRA(const uint32_t * const in_data,int num_pixels,WEBP_CSP_MODE out_colorspace,uint8_t * const rgba)1101 void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
1102 WEBP_CSP_MODE out_colorspace, uint8_t* const rgba) {
1103 switch (out_colorspace) {
1104 case MODE_RGB:
1105 ConvertBGRAToRGB(in_data, num_pixels, rgba);
1106 break;
1107 case MODE_RGBA:
1108 ConvertBGRAToRGBA(in_data, num_pixels, rgba);
1109 break;
1110 case MODE_rgbA:
1111 ConvertBGRAToRGBA(in_data, num_pixels, rgba);
1112 WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);
1113 break;
1114 case MODE_BGR:
1115 ConvertBGRAToBGR(in_data, num_pixels, rgba);
1116 break;
1117 case MODE_BGRA:
1118 CopyOrSwap(in_data, num_pixels, rgba, 1);
1119 break;
1120 case MODE_bgrA:
1121 CopyOrSwap(in_data, num_pixels, rgba, 1);
1122 WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);
1123 break;
1124 case MODE_ARGB:
1125 CopyOrSwap(in_data, num_pixels, rgba, 0);
1126 break;
1127 case MODE_Argb:
1128 CopyOrSwap(in_data, num_pixels, rgba, 0);
1129 WebPApplyAlphaMultiply(rgba, 1, num_pixels, 1, 0);
1130 break;
1131 case MODE_RGBA_4444:
1132 ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
1133 break;
1134 case MODE_rgbA_4444:
1135 ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
1136 WebPApplyAlphaMultiply4444(rgba, num_pixels, 1, 0);
1137 break;
1138 case MODE_RGB_565:
1139 ConvertBGRAToRGB565(in_data, num_pixels, rgba);
1140 break;
1141 default:
1142 assert(0); // Code flow should not reach here.
1143 }
1144 }
1145
1146 //------------------------------------------------------------------------------
1147
1148 #if defined(__cplusplus) || defined(c_plusplus)
1149 } // extern "C"
1150 #endif
1151