Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: third_party/libwebp/dsp/lossless.c

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

Powered by Google App Engine
This is Rietveld 408576698