OLD | NEW |
1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
4 // that can be found in the COPYING file in the root of the source | 4 // that can be found in the COPYING file in the root of the source |
5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
9 // | 9 // |
10 // Author: Jyrki Alakuijala (jyrki@google.com) | 10 // Author: Jyrki Alakuijala (jyrki@google.com) |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 const int iter_mult = (quality < 27) ? 1 : 1 + ((quality - 27) >> 4); | 149 const int iter_mult = (quality < 27) ? 1 : 1 + ((quality - 27) >> 4); |
150 const int iter_neg = -iter_mult * (quality >> 1); | 150 const int iter_neg = -iter_mult * (quality >> 1); |
151 // Limit the backward-ref window size for lower qualities. | 151 // Limit the backward-ref window size for lower qualities. |
152 const int max_window_size = (quality > 50) ? WINDOW_SIZE | 152 const int max_window_size = (quality > 50) ? WINDOW_SIZE |
153 : (quality > 25) ? (xsize << 8) | 153 : (quality > 25) ? (xsize << 8) |
154 : (xsize << 4); | 154 : (xsize << 4); |
155 assert(xsize > 0); | 155 assert(xsize > 0); |
156 *window_size = (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE | 156 *window_size = (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE |
157 : max_window_size; | 157 : max_window_size; |
158 *iter_pos = 8 + (quality >> 3); | 158 *iter_pos = 8 + (quality >> 3); |
159 // For lower entropy images, the rigourous search loop in HashChainFindCopy | 159 // For lower entropy images, the rigorous search loop in HashChainFindCopy |
160 // can be relaxed. | 160 // can be relaxed. |
161 *iter_limit = (cache_bits > 0) ? iter_neg : iter_neg / 2; | 161 *iter_limit = (cache_bits > 0) ? iter_neg : iter_neg / 2; |
162 } | 162 } |
163 | 163 |
164 static int HashChainFindCopy(const HashChain* const p, | 164 static int HashChainFindCopy(const HashChain* const p, |
165 int base_position, int xsize_signed, | 165 int base_position, int xsize_signed, |
166 const uint32_t* const argb, int maxlen, | 166 const uint32_t* const argb, int max_len, |
167 int window_size, int iter_pos, int iter_limit, | 167 int window_size, int iter_pos, int iter_limit, |
168 int* const distance_ptr, | 168 int* const distance_ptr, |
169 int* const length_ptr) { | 169 int* const length_ptr) { |
170 const uint32_t* const argb_start = argb + base_position; | 170 const uint32_t* const argb_start = argb + base_position; |
171 uint64_t best_val = 0; | 171 uint64_t best_val = 0; |
172 uint32_t best_length = 1; | 172 uint32_t best_length = 1; |
173 uint32_t best_distance = 0; | 173 uint32_t best_distance = 0; |
174 const uint32_t xsize = (uint32_t)xsize_signed; | 174 const uint32_t xsize = (uint32_t)xsize_signed; |
175 const int min_pos = | 175 const int min_pos = |
176 (base_position > window_size) ? base_position - window_size : 0; | 176 (base_position > window_size) ? base_position - window_size : 0; |
177 int pos; | 177 int pos; |
178 assert(xsize > 0); | 178 assert(xsize > 0); |
| 179 if (max_len > MAX_LENGTH) { |
| 180 max_len = MAX_LENGTH; |
| 181 } |
179 for (pos = p->hash_to_first_index_[GetPixPairHash64(argb_start)]; | 182 for (pos = p->hash_to_first_index_[GetPixPairHash64(argb_start)]; |
180 pos >= min_pos; | 183 pos >= min_pos; |
181 pos = p->chain_[pos]) { | 184 pos = p->chain_[pos]) { |
182 uint64_t val; | 185 uint64_t val; |
183 uint32_t curr_length; | 186 uint32_t curr_length; |
184 uint32_t distance; | 187 uint32_t distance; |
| 188 const uint64_t* const ptr1 = |
| 189 (const uint64_t*)(argb + pos + best_length - 1); |
| 190 const uint64_t* const ptr2 = |
| 191 (const uint64_t*)(argb_start + best_length - 1); |
| 192 |
185 if (iter_pos < 0) { | 193 if (iter_pos < 0) { |
186 if (iter_pos < iter_limit || best_val >= 0xff0000) { | 194 if (iter_pos < iter_limit || best_val >= 0xff0000) { |
187 break; | 195 break; |
188 } | 196 } |
189 } | 197 } |
190 --iter_pos; | 198 --iter_pos; |
191 if (argb[pos + best_length - 1] != argb_start[best_length - 1]) { | 199 |
192 continue; | 200 // Before 'expensive' linear match, check if the two arrays match at the |
193 } | 201 // current best length index and also for the succeeding elements. |
194 curr_length = FindMatchLength(argb + pos, argb_start, maxlen); | 202 if (*ptr1 != *ptr2) continue; |
195 if (curr_length < best_length) { | 203 |
196 continue; | 204 curr_length = FindMatchLength(argb + pos, argb_start, max_len); |
197 } | 205 if (curr_length < best_length) continue; |
| 206 |
198 distance = (uint32_t)(base_position - pos); | 207 distance = (uint32_t)(base_position - pos); |
199 val = curr_length << 16; | 208 val = curr_length << 16; |
200 // Favoring 2d locality here gives savings for certain images. | 209 // Favoring 2d locality here gives savings for certain images. |
201 if (distance < 9 * xsize) { | 210 if (distance < 9 * xsize) { |
202 const uint32_t y = distance / xsize; | 211 const uint32_t y = distance / xsize; |
203 uint32_t x = distance % xsize; | 212 uint32_t x = distance % xsize; |
204 if (x > (xsize >> 1)) { | 213 if (x > (xsize >> 1)) { |
205 x = xsize - x; | 214 x = xsize - x; |
206 } | 215 } |
207 if (x <= 7) { | 216 if (x <= 7) { |
208 val += 9 * 9 + 9 * 9; | 217 val += 9 * 9 + 9 * 9; |
209 val -= y * y + x * x; | 218 val -= y * y + x * x; |
210 } | 219 } |
211 } | 220 } |
212 if (best_val < val) { | 221 if (best_val < val) { |
213 best_val = val; | 222 best_val = val; |
214 best_length = curr_length; | 223 best_length = curr_length; |
215 best_distance = distance; | 224 best_distance = distance; |
216 if (curr_length >= MAX_LENGTH) { | 225 if (curr_length >= (uint32_t)max_len) { |
217 break; | 226 break; |
218 } | 227 } |
219 if ((best_distance == 1 || distance == xsize) && | 228 if ((best_distance == 1 || distance == xsize) && |
220 best_length >= 128) { | 229 best_length >= 128) { |
221 break; | 230 break; |
222 } | 231 } |
223 } | 232 } |
224 } | 233 } |
225 *distance_ptr = (int)best_distance; | 234 *distance_ptr = (int)best_distance; |
226 *length_ptr = best_length; | 235 *length_ptr = best_length; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 if (!HashChainInit(hash_chain, pix_count)) goto Error; | 293 if (!HashChainInit(hash_chain, pix_count)) goto Error; |
285 | 294 |
286 refs->size = 0; | 295 refs->size = 0; |
287 GetParamsForHashChainFindCopy(quality, xsize, cache_bits, | 296 GetParamsForHashChainFindCopy(quality, xsize, cache_bits, |
288 &window_size, &iter_pos, &iter_limit); | 297 &window_size, &iter_pos, &iter_limit); |
289 for (i = 0; i < pix_count; ) { | 298 for (i = 0; i < pix_count; ) { |
290 // Alternative#1: Code the pixels starting at 'i' using backward reference. | 299 // Alternative#1: Code the pixels starting at 'i' using backward reference. |
291 int offset = 0; | 300 int offset = 0; |
292 int len = 0; | 301 int len = 0; |
293 if (i < pix_count - 1) { // FindCopy(i,..) reads pixels at [i] and [i + 1]. | 302 if (i < pix_count - 1) { // FindCopy(i,..) reads pixels at [i] and [i + 1]. |
294 int maxlen = pix_count - i; | 303 int max_len = pix_count - i; |
295 if (maxlen > MAX_LENGTH) { | 304 HashChainFindCopy(hash_chain, i, xsize, argb, max_len, |
296 maxlen = MAX_LENGTH; | |
297 } | |
298 HashChainFindCopy(hash_chain, i, xsize, argb, maxlen, | |
299 window_size, iter_pos, iter_limit, | 305 window_size, iter_pos, iter_limit, |
300 &offset, &len); | 306 &offset, &len); |
301 } | 307 } |
302 if (len >= MIN_LENGTH) { | 308 if (len >= MIN_LENGTH) { |
303 // Alternative#2: Insert the pixel at 'i' as literal, and code the | 309 // Alternative#2: Insert the pixel at 'i' as literal, and code the |
304 // pixels starting at 'i + 1' using backward reference. | 310 // pixels starting at 'i + 1' using backward reference. |
305 int offset2 = 0; | 311 int offset2 = 0; |
306 int len2 = 0; | 312 int len2 = 0; |
307 int k; | 313 int k; |
308 HashChainInsert(hash_chain, &argb[i], i); | 314 HashChainInsert(hash_chain, &argb[i], i); |
309 if (i < pix_count - 2) { // FindCopy(i+1,..) reads [i + 1] and [i + 2]. | 315 if (i < pix_count - 2) { // FindCopy(i+1,..) reads [i + 1] and [i + 2]. |
310 int maxlen = pix_count - (i + 1); | 316 int max_len = pix_count - (i + 1); |
311 if (maxlen > MAX_LENGTH) { | 317 HashChainFindCopy(hash_chain, i + 1, xsize, argb, max_len, |
312 maxlen = MAX_LENGTH; | |
313 } | |
314 HashChainFindCopy(hash_chain, i + 1, xsize, argb, maxlen, | |
315 window_size, iter_pos, iter_limit, | 318 window_size, iter_pos, iter_limit, |
316 &offset2, &len2); | 319 &offset2, &len2); |
317 if (len2 > len + 1) { | 320 if (len2 > len + 1) { |
318 const uint32_t pixel = argb[i]; | 321 const uint32_t pixel = argb[i]; |
319 // Alternative#2 is a better match. So push pixel at 'i' as literal. | 322 // Alternative#2 is a better match. So push pixel at 'i' as literal. |
320 if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) { | 323 if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) { |
321 const int ix = VP8LColorCacheGetIndex(&hashers, pixel); | 324 const int ix = VP8LColorCacheGetIndex(&hashers, pixel); |
322 refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix); | 325 refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix); |
323 } else { | 326 } else { |
| 327 if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel); |
324 refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel); | 328 refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel); |
325 } | 329 } |
326 ++refs->size; | 330 ++refs->size; |
327 if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel); | |
328 i++; // Backward reference to be done for next pixel. | 331 i++; // Backward reference to be done for next pixel. |
329 len = len2; | 332 len = len2; |
330 offset = offset2; | 333 offset = offset2; |
331 } | 334 } |
332 } | 335 } |
333 if (len >= MAX_LENGTH) { | 336 if (len >= MAX_LENGTH) { |
334 len = MAX_LENGTH - 1; | 337 len = MAX_LENGTH - 1; |
335 } | 338 } |
336 refs->refs[refs->size++] = PixOrCopyCreateCopy(offset, len); | 339 refs->refs[refs->size++] = PixOrCopyCreateCopy(offset, len); |
337 if (use_color_cache) { | 340 if (use_color_cache) { |
338 for (k = 0; k < len; ++k) { | 341 for (k = 0; k < len; ++k) { |
339 VP8LColorCacheInsert(&hashers, argb[i + k]); | 342 VP8LColorCacheInsert(&hashers, argb[i + k]); |
340 } | 343 } |
341 } | 344 } |
342 // Add to the hash_chain (but cannot add the last pixel). | 345 // Add to the hash_chain (but cannot add the last pixel). |
343 { | 346 { |
344 const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i; | 347 const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i; |
345 for (k = 1; k < last; ++k) { | 348 for (k = 1; k < last; ++k) { |
346 HashChainInsert(hash_chain, &argb[i + k], i + k); | 349 HashChainInsert(hash_chain, &argb[i + k], i + k); |
347 } | 350 } |
348 } | 351 } |
349 i += len; | 352 i += len; |
350 } else { | 353 } else { |
351 const uint32_t pixel = argb[i]; | 354 const uint32_t pixel = argb[i]; |
352 if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) { | 355 if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) { |
353 // push pixel as a PixOrCopyCreateCacheIdx pixel | 356 // push pixel as a PixOrCopyCreateCacheIdx pixel |
354 const int ix = VP8LColorCacheGetIndex(&hashers, pixel); | 357 const int ix = VP8LColorCacheGetIndex(&hashers, pixel); |
355 refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix); | 358 refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix); |
356 } else { | 359 } else { |
| 360 if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel); |
357 refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel); | 361 refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel); |
358 } | 362 } |
359 ++refs->size; | 363 ++refs->size; |
360 if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel); | |
361 if (i + 1 < pix_count) { | 364 if (i + 1 < pix_count) { |
362 HashChainInsert(hash_chain, &argb[i], i); | 365 HashChainInsert(hash_chain, &argb[i], i); |
363 } | 366 } |
364 ++i; | 367 ++i; |
365 } | 368 } |
366 } | 369 } |
367 ok = 1; | 370 ok = 1; |
368 Error: | 371 Error: |
369 if (cc_init) VP8LColorCacheClear(&hashers); | 372 if (cc_init) VP8LColorCacheClear(&hashers); |
370 HashChainDelete(hash_chain); | 373 HashChainDelete(hash_chain); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 m->blue_[v & 0xff]; | 455 m->blue_[v & 0xff]; |
453 } | 456 } |
454 | 457 |
455 static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) { | 458 static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) { |
456 const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx; | 459 const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx; |
457 return m->literal_[literal_idx]; | 460 return m->literal_[literal_idx]; |
458 } | 461 } |
459 | 462 |
460 static WEBP_INLINE double GetLengthCost(const CostModel* const m, | 463 static WEBP_INLINE double GetLengthCost(const CostModel* const m, |
461 uint32_t length) { | 464 uint32_t length) { |
462 int code, extra_bits_count, extra_bits_value; | 465 int code, extra_bits; |
463 PrefixEncode(length, &code, &extra_bits_count, &extra_bits_value); | 466 VP8LPrefixEncodeBits(length, &code, &extra_bits); |
464 return m->literal_[VALUES_IN_BYTE + code] + extra_bits_count; | 467 return m->literal_[VALUES_IN_BYTE + code] + extra_bits; |
465 } | 468 } |
466 | 469 |
467 static WEBP_INLINE double GetDistanceCost(const CostModel* const m, | 470 static WEBP_INLINE double GetDistanceCost(const CostModel* const m, |
468 uint32_t distance) { | 471 uint32_t distance) { |
469 int code, extra_bits_count, extra_bits_value; | 472 int code, extra_bits; |
470 PrefixEncode(distance, &code, &extra_bits_count, &extra_bits_value); | 473 VP8LPrefixEncodeBits(distance, &code, &extra_bits); |
471 return m->distance_[code] + extra_bits_count; | 474 return m->distance_[code] + extra_bits; |
472 } | 475 } |
473 | 476 |
474 static int BackwardReferencesHashChainDistanceOnly( | 477 static int BackwardReferencesHashChainDistanceOnly( |
475 int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb, | 478 int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb, |
476 int quality, int cache_bits, uint32_t* const dist_array) { | 479 int quality, int cache_bits, uint32_t* const dist_array) { |
477 int i; | 480 int i; |
478 int ok = 0; | 481 int ok = 0; |
479 int cc_init = 0; | 482 int cc_init = 0; |
480 const int pix_count = xsize * ysize; | 483 const int pix_count = xsize * ysize; |
481 const int use_color_cache = (cache_bits > 0); | 484 const int use_color_cache = (cache_bits > 0); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
515 for (i = 0; i < pix_count; ++i) { | 518 for (i = 0; i < pix_count; ++i) { |
516 double prev_cost = 0.0; | 519 double prev_cost = 0.0; |
517 int shortmax; | 520 int shortmax; |
518 if (i > 0) { | 521 if (i > 0) { |
519 prev_cost = cost[i - 1]; | 522 prev_cost = cost[i - 1]; |
520 } | 523 } |
521 for (shortmax = 0; shortmax < 2; ++shortmax) { | 524 for (shortmax = 0; shortmax < 2; ++shortmax) { |
522 int offset = 0; | 525 int offset = 0; |
523 int len = 0; | 526 int len = 0; |
524 if (i < pix_count - 1) { // FindCopy reads pixels at [i] and [i + 1]. | 527 if (i < pix_count - 1) { // FindCopy reads pixels at [i] and [i + 1]. |
525 int maxlen = shortmax ? 2 : MAX_LENGTH; | 528 int max_len = shortmax ? 2 : pix_count - i; |
526 if (maxlen > pix_count - i) { | 529 HashChainFindCopy(hash_chain, i, xsize, argb, max_len, |
527 maxlen = pix_count - i; | |
528 } | |
529 HashChainFindCopy(hash_chain, i, xsize, argb, maxlen, | |
530 window_size, iter_pos, iter_limit, | 530 window_size, iter_pos, iter_limit, |
531 &offset, &len); | 531 &offset, &len); |
532 } | 532 } |
533 if (len >= MIN_LENGTH) { | 533 if (len >= MIN_LENGTH) { |
534 const int code = DistanceToPlaneCode(xsize, offset); | 534 const int code = DistanceToPlaneCode(xsize, offset); |
535 const double distance_cost = | 535 const double distance_cost = |
536 prev_cost + GetDistanceCost(cost_model, code); | 536 prev_cost + GetDistanceCost(cost_model, code); |
537 int k; | 537 int k; |
538 for (k = 1; k < len; ++k) { | 538 for (k = 1; k < len; ++k) { |
539 const double cost_val = distance_cost + GetLengthCost(cost_model, k); | 539 const double cost_val = distance_cost + GetLengthCost(cost_model, k); |
(...skipping 30 matching lines...) Expand all Loading... |
570 if (i < pix_count - 1) { | 570 if (i < pix_count - 1) { |
571 HashChainInsert(hash_chain, &argb[i], i); | 571 HashChainInsert(hash_chain, &argb[i], i); |
572 } | 572 } |
573 { | 573 { |
574 // inserting a literal pixel | 574 // inserting a literal pixel |
575 double cost_val = prev_cost; | 575 double cost_val = prev_cost; |
576 if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) { | 576 if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) { |
577 const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]); | 577 const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]); |
578 cost_val += GetCacheCost(cost_model, ix) * mul0; | 578 cost_val += GetCacheCost(cost_model, ix) * mul0; |
579 } else { | 579 } else { |
| 580 if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); |
580 cost_val += GetLiteralCost(cost_model, argb[i]) * mul1; | 581 cost_val += GetLiteralCost(cost_model, argb[i]) * mul1; |
581 } | 582 } |
582 if (cost[i] > cost_val) { | 583 if (cost[i] > cost_val) { |
583 cost[i] = (float)cost_val; | 584 cost[i] = (float)cost_val; |
584 dist_array[i] = 1; // only one is inserted. | 585 dist_array[i] = 1; // only one is inserted. |
585 } | 586 } |
586 if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); | |
587 } | 587 } |
588 next_symbol: ; | 588 next_symbol: ; |
589 } | 589 } |
590 // Last pixel still to do, it can only be a single step if not reached | 590 // Last pixel still to do, it can only be a single step if not reached |
591 // through cheaper means already. | 591 // through cheaper means already. |
592 ok = 1; | 592 ok = 1; |
593 Error: | 593 Error: |
594 if (cc_init) VP8LColorCacheClear(&hashers); | 594 if (cc_init) VP8LColorCacheClear(&hashers); |
595 HashChainDelete(hash_chain); | 595 HashChainDelete(hash_chain); |
596 free(cost_model); | 596 free(cost_model); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 cc_init = VP8LColorCacheInit(&hashers, cache_bits); | 643 cc_init = VP8LColorCacheInit(&hashers, cache_bits); |
644 if (!cc_init) goto Error; | 644 if (!cc_init) goto Error; |
645 } | 645 } |
646 | 646 |
647 refs->size = 0; | 647 refs->size = 0; |
648 GetParamsForHashChainFindCopy(quality, xsize, cache_bits, | 648 GetParamsForHashChainFindCopy(quality, xsize, cache_bits, |
649 &window_size, &iter_pos, &iter_limit); | 649 &window_size, &iter_pos, &iter_limit); |
650 for (ix = 0; ix < chosen_path_size; ++ix, ++size) { | 650 for (ix = 0; ix < chosen_path_size; ++ix, ++size) { |
651 int offset = 0; | 651 int offset = 0; |
652 int len = 0; | 652 int len = 0; |
653 int maxlen = chosen_path[ix]; | 653 int max_len = chosen_path[ix]; |
654 if (maxlen != 1) { | 654 if (max_len != 1) { |
655 HashChainFindCopy(hash_chain, i, xsize, argb, maxlen, | 655 HashChainFindCopy(hash_chain, i, xsize, argb, max_len, |
656 window_size, iter_pos, iter_limit, | 656 window_size, iter_pos, iter_limit, |
657 &offset, &len); | 657 &offset, &len); |
658 assert(len == maxlen); | 658 assert(len == max_len); |
659 refs->refs[size] = PixOrCopyCreateCopy(offset, len); | 659 refs->refs[size] = PixOrCopyCreateCopy(offset, len); |
660 if (use_color_cache) { | 660 if (use_color_cache) { |
661 for (k = 0; k < len; ++k) { | 661 for (k = 0; k < len; ++k) { |
662 VP8LColorCacheInsert(&hashers, argb[i + k]); | 662 VP8LColorCacheInsert(&hashers, argb[i + k]); |
663 } | 663 } |
664 } | 664 } |
665 { | 665 { |
666 const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i; | 666 const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i; |
667 for (k = 0; k < last; ++k) { | 667 for (k = 0; k < last; ++k) { |
668 HashChainInsert(hash_chain, &argb[i + k], i + k); | 668 HashChainInsert(hash_chain, &argb[i + k], i + k); |
669 } | 669 } |
670 } | 670 } |
671 i += len; | 671 i += len; |
672 } else { | 672 } else { |
673 if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) { | 673 if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) { |
674 // push pixel as a color cache index | 674 // push pixel as a color cache index |
675 const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]); | 675 const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]); |
676 refs->refs[size] = PixOrCopyCreateCacheIdx(idx); | 676 refs->refs[size] = PixOrCopyCreateCacheIdx(idx); |
677 } else { | 677 } else { |
| 678 if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); |
678 refs->refs[size] = PixOrCopyCreateLiteral(argb[i]); | 679 refs->refs[size] = PixOrCopyCreateLiteral(argb[i]); |
679 } | 680 } |
680 if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); | |
681 if (i + 1 < pix_count) { | 681 if (i + 1 < pix_count) { |
682 HashChainInsert(hash_chain, &argb[i], i); | 682 HashChainInsert(hash_chain, &argb[i], i); |
683 } | 683 } |
684 ++i; | 684 ++i; |
685 } | 685 } |
686 } | 686 } |
687 assert(size <= refs->max_size); | 687 assert(size <= refs->max_size); |
688 refs->size = size; | 688 refs->size = size; |
689 ok = 1; | 689 ok = 1; |
690 Error: | 690 Error: |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
773 // Evaluate RLE coding | 773 // Evaluate RLE coding |
774 VP8LHistogramCreate(histo, &refs_rle, cache_bits); | 774 VP8LHistogramCreate(histo, &refs_rle, cache_bits); |
775 bit_cost_rle = VP8LHistogramEstimateBits(histo); | 775 bit_cost_rle = VP8LHistogramEstimateBits(histo); |
776 // Decide if LZ77 is useful. | 776 // Decide if LZ77 is useful. |
777 lz77_is_useful = (bit_cost_lz77 < bit_cost_rle); | 777 lz77_is_useful = (bit_cost_lz77 < bit_cost_rle); |
778 free(histo); | 778 free(histo); |
779 } | 779 } |
780 | 780 |
781 // Choose appropriate backward reference. | 781 // Choose appropriate backward reference. |
782 if (lz77_is_useful) { | 782 if (lz77_is_useful) { |
783 // TraceBackwards is costly. Don't execute it at lower quality (q <= 10). | 783 // TraceBackwards is costly. Don't execute it at lower quality. |
784 const int try_lz77_trace_backwards = (quality > 10); | 784 const int try_lz77_trace_backwards = (quality >= 25); |
785 *best = refs_lz77; // default guess: lz77 is better | 785 *best = refs_lz77; // default guess: lz77 is better |
786 VP8LClearBackwardRefs(&refs_rle); | 786 VP8LClearBackwardRefs(&refs_rle); |
787 if (try_lz77_trace_backwards) { | 787 if (try_lz77_trace_backwards) { |
788 // Set recursion level for large images using a color cache. | 788 // Set recursion level for large images using a color cache. |
789 const int recursion_level = | 789 const int recursion_level = |
790 (num_pix < 320 * 200) && (cache_bits > 0) ? 1 : 0; | 790 (num_pix < 320 * 200) && (cache_bits > 0) ? 1 : 0; |
791 VP8LBackwardRefs refs_trace; | 791 VP8LBackwardRefs refs_trace; |
792 if (!VP8LBackwardRefsAlloc(&refs_trace, num_pix)) { | 792 if (!VP8LBackwardRefsAlloc(&refs_trace, num_pix)) { |
793 goto End; | 793 goto End; |
794 } | 794 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
885 if (cache_bits == 0 || cur_entropy < lowest_entropy) { | 885 if (cache_bits == 0 || cur_entropy < lowest_entropy) { |
886 *best_cache_bits = cache_bits; | 886 *best_cache_bits = cache_bits; |
887 lowest_entropy = cur_entropy; | 887 lowest_entropy = cur_entropy; |
888 } | 888 } |
889 } | 889 } |
890 ok = 1; | 890 ok = 1; |
891 Error: | 891 Error: |
892 VP8LClearBackwardRefs(&refs); | 892 VP8LClearBackwardRefs(&refs); |
893 return ok; | 893 return ok; |
894 } | 894 } |
OLD | NEW |