• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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