| 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 |