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

Side by Side Diff: third_party/libwebp/enc/backward_references.c

Issue 12942006: libwebp: update snapshot to v0.3.0-rc6 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 9 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
« no previous file with comments | « third_party/libwebp/enc/backward_references.h ('k') | third_party/libwebp/enc/config.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 Google Inc. All Rights Reserved.
2 // 2 //
3 // This code is licensed under the same terms as WebM: 3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/ 4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // ----------------------------------------------------------------------------- 6 // -----------------------------------------------------------------------------
7 // 7 //
8 // Author: Jyrki Alakuijala (jyrki@google.com) 8 // Author: Jyrki Alakuijala (jyrki@google.com)
9 // 9 //
10 10
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 } 134 }
135 135
136 // Insertion of two pixels at a time. 136 // Insertion of two pixels at a time.
137 static void HashChainInsert(HashChain* const p, 137 static void HashChainInsert(HashChain* const p,
138 const uint32_t* const argb, int pos) { 138 const uint32_t* const argb, int pos) {
139 const uint64_t hash_code = GetPixPairHash64(argb); 139 const uint64_t hash_code = GetPixPairHash64(argb);
140 p->chain_[pos] = p->hash_to_first_index_[hash_code]; 140 p->chain_[pos] = p->hash_to_first_index_[hash_code];
141 p->hash_to_first_index_[hash_code] = pos; 141 p->hash_to_first_index_[hash_code] = pos;
142 } 142 }
143 143
144 static void GetParamsForHashChainFindCopy(int quality, int xsize,
145 int* window_size, int* iter_pos,
146 int* iter_limit) {
147 const int iter_mult = (quality < 27) ? 1 : 1 + ((quality - 27) >> 4);
148 // Limit the backward-ref window size for lower qualities.
149 const int max_window_size = (quality > 50) ? WINDOW_SIZE
150 : (quality > 25) ? (xsize << 8)
151 : (xsize << 4);
152 assert(xsize > 0);
153 *window_size = (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE
154 : max_window_size;
155 *iter_pos = 5 + (quality >> 3);
156 *iter_limit = -quality * iter_mult;
157 }
158
144 static int HashChainFindCopy(const HashChain* const p, 159 static int HashChainFindCopy(const HashChain* const p,
145 int quality, int index, int xsize, 160 int base_position, int xsize,
146 const uint32_t* const argb, int maxlen, 161 const uint32_t* const argb, int maxlen,
162 int window_size, int iter_pos, int iter_limit,
147 int* const distance_ptr, 163 int* const distance_ptr,
148 int* const length_ptr) { 164 int* const length_ptr) {
149 const uint64_t hash_code = GetPixPairHash64(&argb[index]); 165 const uint64_t hash_code = GetPixPairHash64(&argb[base_position]);
150 int prev_length = 0; 166 int prev_length = 0;
151 int64_t best_val = 0; 167 int64_t best_val = 0;
152 int best_length = 0; 168 int best_length = 0;
153 int best_distance = 0; 169 int best_distance = 0;
154 const uint32_t* const argb_start = argb + index; 170 const uint32_t* const argb_start = argb + base_position;
155 const int iter_min_mult = (quality < 50) ? 2 : (quality < 75) ? 4 : 8; 171 const int min_pos =
156 const int iter_min = -quality * iter_min_mult; 172 (base_position > window_size) ? base_position - window_size : 0;
157 int iter_cnt = 10 + (quality >> 1);
158 const int min_pos = (index > WINDOW_SIZE) ? index - WINDOW_SIZE : 0;
159 int pos; 173 int pos;
160 174
161 assert(xsize > 0); 175 assert(xsize > 0);
162 for (pos = p->hash_to_first_index_[hash_code]; 176 for (pos = p->hash_to_first_index_[hash_code];
163 pos >= min_pos; 177 pos >= min_pos;
164 pos = p->chain_[pos]) { 178 pos = p->chain_[pos]) {
165 int64_t val; 179 int64_t val;
166 int curr_length; 180 int curr_length;
167 if (iter_cnt < 0) { 181 if (iter_pos < 0) {
168 if (iter_cnt < iter_min || best_val >= 0xff0000) { 182 if (iter_pos < iter_limit || best_val >= 0xff0000) {
169 break; 183 break;
170 } 184 }
171 } 185 }
172 --iter_cnt; 186 --iter_pos;
173 if (best_length != 0 && 187 if (best_length != 0 &&
174 argb[pos + best_length - 1] != argb_start[best_length - 1]) { 188 argb[pos + best_length - 1] != argb_start[best_length - 1]) {
175 continue; 189 continue;
176 } 190 }
177 curr_length = FindMatchLength(argb + pos, argb_start, maxlen); 191 curr_length = FindMatchLength(argb + pos, argb_start, maxlen);
178 if (curr_length < prev_length) { 192 if (curr_length < prev_length) {
179 continue; 193 continue;
180 } 194 }
181 val = 65536 * curr_length; 195 val = 65536 * curr_length;
182 // Favoring 2d locality here gives savings for certain images. 196 // Favoring 2d locality here gives savings for certain images.
183 if (index - pos < 9 * xsize) { 197 if (base_position - pos < 9 * xsize) {
184 const int y = (index - pos) / xsize; 198 const int y = (base_position - pos) / xsize;
185 int x = (index - pos) % xsize; 199 int x = (base_position - pos) % xsize;
186 if (x > xsize / 2) { 200 if (x > xsize / 2) {
187 x = xsize - x; 201 x = xsize - x;
188 } 202 }
189 if (x <= 7 && x >= -8) { 203 if (x <= 7 && x >= -8) {
190 val -= y * y + x * x; 204 val -= y * y + x * x;
191 } else { 205 } else {
192 val -= 9 * 9 + 9 * 9; 206 val -= 9 * 9 + 9 * 9;
193 } 207 }
194 } else { 208 } else {
195 val -= 9 * 9 + 9 * 9; 209 val -= 9 * 9 + 9 * 9;
196 } 210 }
197 if (best_val < val) { 211 if (best_val < val) {
198 prev_length = curr_length; 212 prev_length = curr_length;
199 best_val = val; 213 best_val = val;
200 best_length = curr_length; 214 best_length = curr_length;
201 best_distance = index - pos; 215 best_distance = base_position - pos;
202 if (curr_length >= MAX_LENGTH) { 216 if (curr_length >= MAX_LENGTH) {
203 break; 217 break;
204 } 218 }
205 if ((best_distance == 1 || best_distance == xsize) && 219 if ((best_distance == 1 || best_distance == xsize) &&
206 best_length >= 128) { 220 best_length >= 128) {
207 break; 221 break;
208 } 222 }
209 } 223 }
210 } 224 }
211 *distance_ptr = best_distance; 225 *distance_ptr = best_distance;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 const uint32_t* const argb, 264 const uint32_t* const argb,
251 int cache_bits, int quality, 265 int cache_bits, int quality,
252 VP8LBackwardRefs* const refs) { 266 VP8LBackwardRefs* const refs) {
253 int i; 267 int i;
254 int ok = 0; 268 int ok = 0;
255 int cc_init = 0; 269 int cc_init = 0;
256 const int use_color_cache = (cache_bits > 0); 270 const int use_color_cache = (cache_bits > 0);
257 const int pix_count = xsize * ysize; 271 const int pix_count = xsize * ysize;
258 HashChain* const hash_chain = (HashChain*)malloc(sizeof(*hash_chain)); 272 HashChain* const hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
259 VP8LColorCache hashers; 273 VP8LColorCache hashers;
274 int window_size = WINDOW_SIZE;
275 int iter_pos = 1;
276 int iter_limit = -1;
260 277
261 if (hash_chain == NULL) return 0; 278 if (hash_chain == NULL) return 0;
262 if (use_color_cache) { 279 if (use_color_cache) {
263 cc_init = VP8LColorCacheInit(&hashers, cache_bits); 280 cc_init = VP8LColorCacheInit(&hashers, cache_bits);
264 if (!cc_init) goto Error; 281 if (!cc_init) goto Error;
265 } 282 }
266 283
267 if (!HashChainInit(hash_chain, pix_count)) goto Error; 284 if (!HashChainInit(hash_chain, pix_count)) goto Error;
268 285
269 refs->size = 0; 286 refs->size = 0;
287 GetParamsForHashChainFindCopy(quality, xsize, &window_size, &iter_pos,
288 &iter_limit);
270 for (i = 0; i < pix_count; ) { 289 for (i = 0; i < pix_count; ) {
271 // Alternative#1: Code the pixels starting at 'i' using backward reference. 290 // Alternative#1: Code the pixels starting at 'i' using backward reference.
272 int offset = 0; 291 int offset = 0;
273 int len = 0; 292 int len = 0;
274 if (i < pix_count - 1) { // FindCopy(i,..) reads pixels at [i] and [i + 1]. 293 if (i < pix_count - 1) { // FindCopy(i,..) reads pixels at [i] and [i + 1].
275 int maxlen = pix_count - i; 294 int maxlen = pix_count - i;
276 if (maxlen > MAX_LENGTH) { 295 if (maxlen > MAX_LENGTH) {
277 maxlen = MAX_LENGTH; 296 maxlen = MAX_LENGTH;
278 } 297 }
279 HashChainFindCopy(hash_chain, quality, i, xsize, argb, maxlen, 298 HashChainFindCopy(hash_chain, i, xsize, argb, maxlen,
299 window_size, iter_pos, iter_limit,
280 &offset, &len); 300 &offset, &len);
281 } 301 }
282 if (len >= MIN_LENGTH) { 302 if (len >= MIN_LENGTH) {
283 // Alternative#2: Insert the pixel at 'i' as literal, and code the 303 // Alternative#2: Insert the pixel at 'i' as literal, and code the
284 // pixels starting at 'i + 1' using backward reference. 304 // pixels starting at 'i + 1' using backward reference.
285 int offset2 = 0; 305 int offset2 = 0;
286 int len2 = 0; 306 int len2 = 0;
287 int k; 307 int k;
288 HashChainInsert(hash_chain, &argb[i], i); 308 HashChainInsert(hash_chain, &argb[i], i);
289 if (i < pix_count - 2) { // FindCopy(i+1,..) reads [i + 1] and [i + 2]. 309 if (i < pix_count - 2) { // FindCopy(i+1,..) reads [i + 1] and [i + 2].
290 int maxlen = pix_count - (i + 1); 310 int maxlen = pix_count - (i + 1);
291 if (maxlen > MAX_LENGTH) { 311 if (maxlen > MAX_LENGTH) {
292 maxlen = MAX_LENGTH; 312 maxlen = MAX_LENGTH;
293 } 313 }
294 HashChainFindCopy(hash_chain, quality, 314 HashChainFindCopy(hash_chain, i + 1, xsize, argb, maxlen,
295 i + 1, xsize, argb, maxlen, &offset2, &len2); 315 window_size, iter_pos, iter_limit,
316 &offset2, &len2);
296 if (len2 > len + 1) { 317 if (len2 > len + 1) {
297 const uint32_t pixel = argb[i]; 318 const uint32_t pixel = argb[i];
298 // Alternative#2 is a better match. So push pixel at 'i' as literal. 319 // Alternative#2 is a better match. So push pixel at 'i' as literal.
299 if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) { 320 if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
300 const int ix = VP8LColorCacheGetIndex(&hashers, pixel); 321 const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
301 refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix); 322 refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix);
302 } else { 323 } else {
303 refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel); 324 refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel);
304 } 325 }
305 ++refs->size; 326 ++refs->size;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 typedef struct { 376 typedef struct {
356 double alpha_[VALUES_IN_BYTE]; 377 double alpha_[VALUES_IN_BYTE];
357 double red_[VALUES_IN_BYTE]; 378 double red_[VALUES_IN_BYTE];
358 double literal_[PIX_OR_COPY_CODES_MAX]; 379 double literal_[PIX_OR_COPY_CODES_MAX];
359 double blue_[VALUES_IN_BYTE]; 380 double blue_[VALUES_IN_BYTE];
360 double distance_[NUM_DISTANCE_CODES]; 381 double distance_[NUM_DISTANCE_CODES];
361 } CostModel; 382 } CostModel;
362 383
363 static int BackwardReferencesTraceBackwards( 384 static int BackwardReferencesTraceBackwards(
364 int xsize, int ysize, int recursive_cost_model, 385 int xsize, int ysize, int recursive_cost_model,
365 const uint32_t* const argb, int cache_bits, VP8LBackwardRefs* const refs); 386 const uint32_t* const argb, int quality, int cache_bits,
387 VP8LBackwardRefs* const refs);
366 388
367 static void ConvertPopulationCountTableToBitEstimates( 389 static void ConvertPopulationCountTableToBitEstimates(
368 int num_symbols, const int population_counts[], double output[]) { 390 int num_symbols, const int population_counts[], double output[]) {
369 int sum = 0; 391 int sum = 0;
370 int nonzeros = 0; 392 int nonzeros = 0;
371 int i; 393 int i;
372 for (i = 0; i < num_symbols; ++i) { 394 for (i = 0; i < num_symbols; ++i) {
373 sum += population_counts[i]; 395 sum += population_counts[i];
374 if (population_counts[i] > 0) { 396 if (population_counts[i] > 0) {
375 ++nonzeros; 397 ++nonzeros;
376 } 398 }
377 } 399 }
378 if (nonzeros <= 1) { 400 if (nonzeros <= 1) {
379 memset(output, 0, num_symbols * sizeof(*output)); 401 memset(output, 0, num_symbols * sizeof(*output));
380 } else { 402 } else {
381 const double logsum = VP8LFastLog2(sum); 403 const double logsum = VP8LFastLog2(sum);
382 for (i = 0; i < num_symbols; ++i) { 404 for (i = 0; i < num_symbols; ++i) {
383 output[i] = logsum - VP8LFastLog2(population_counts[i]); 405 output[i] = logsum - VP8LFastLog2(population_counts[i]);
384 } 406 }
385 } 407 }
386 } 408 }
387 409
388 static int CostModelBuild(CostModel* const m, int xsize, int ysize, 410 static int CostModelBuild(CostModel* const m, int xsize, int ysize,
389 int recursion_level, const uint32_t* const argb, 411 int recursion_level, const uint32_t* const argb,
390 int cache_bits) { 412 int quality, int cache_bits) {
391 int ok = 0; 413 int ok = 0;
392 VP8LHistogram histo; 414 VP8LHistogram histo;
393 VP8LBackwardRefs refs; 415 VP8LBackwardRefs refs;
394 const int quality = 100;
395 416
396 if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize)) goto Error; 417 if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize)) goto Error;
397 418
398 if (recursion_level > 0) { 419 if (recursion_level > 0) {
399 if (!BackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1, 420 if (!BackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1,
400 argb, cache_bits, &refs)) { 421 argb, quality, cache_bits, &refs)) {
401 goto Error; 422 goto Error;
402 } 423 }
403 } else { 424 } else {
404 if (!BackwardReferencesHashChain(xsize, ysize, argb, cache_bits, quality, 425 if (!BackwardReferencesHashChain(xsize, ysize, argb, cache_bits, quality,
405 &refs)) { 426 &refs)) {
406 goto Error; 427 goto Error;
407 } 428 }
408 } 429 }
409 VP8LHistogramCreate(&histo, &refs, cache_bits); 430 VP8LHistogramCreate(&histo, &refs, cache_bits);
410 ConvertPopulationCountTableToBitEstimates( 431 ConvertPopulationCountTableToBitEstimates(
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 466
446 static WEBP_INLINE double GetDistanceCost(const CostModel* const m, 467 static WEBP_INLINE double GetDistanceCost(const CostModel* const m,
447 uint32_t distance) { 468 uint32_t distance) {
448 int code, extra_bits_count, extra_bits_value; 469 int code, extra_bits_count, extra_bits_value;
449 PrefixEncode(distance, &code, &extra_bits_count, &extra_bits_value); 470 PrefixEncode(distance, &code, &extra_bits_count, &extra_bits_value);
450 return m->distance_[code] + extra_bits_count; 471 return m->distance_[code] + extra_bits_count;
451 } 472 }
452 473
453 static int BackwardReferencesHashChainDistanceOnly( 474 static int BackwardReferencesHashChainDistanceOnly(
454 int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb, 475 int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb,
455 int cache_bits, uint32_t* const dist_array) { 476 int quality, int cache_bits, uint32_t* const dist_array) {
456 int i; 477 int i;
457 int ok = 0; 478 int ok = 0;
458 int cc_init = 0; 479 int cc_init = 0;
459 const int quality = 100;
460 const int pix_count = xsize * ysize; 480 const int pix_count = xsize * ysize;
461 const int use_color_cache = (cache_bits > 0); 481 const int use_color_cache = (cache_bits > 0);
462 double* const cost = 482 float* const cost =
463 (double*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost)); 483 (float*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost));
464 CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model)); 484 CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model));
465 HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain)); 485 HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
466 VP8LColorCache hashers; 486 VP8LColorCache hashers;
467 const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68; 487 const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68;
468 const double mul1 = (recursive_cost_model != 0) ? 1.0 : 0.82; 488 const double mul1 = (recursive_cost_model != 0) ? 1.0 : 0.82;
489 const int min_distance_code = 2; // TODO(vikasa): tune as function of quality
490 int window_size = WINDOW_SIZE;
491 int iter_pos = 1;
492 int iter_limit = -1;
469 493
470 if (cost == NULL || cost_model == NULL || hash_chain == NULL) goto Error; 494 if (cost == NULL || cost_model == NULL || hash_chain == NULL) goto Error;
471 495
472 if (!HashChainInit(hash_chain, pix_count)) goto Error; 496 if (!HashChainInit(hash_chain, pix_count)) goto Error;
473 497
474 if (use_color_cache) { 498 if (use_color_cache) {
475 cc_init = VP8LColorCacheInit(&hashers, cache_bits); 499 cc_init = VP8LColorCacheInit(&hashers, cache_bits);
476 if (!cc_init) goto Error; 500 if (!cc_init) goto Error;
477 } 501 }
478 502
479 if (!CostModelBuild(cost_model, xsize, ysize, recursive_cost_model, argb, 503 if (!CostModelBuild(cost_model, xsize, ysize, recursive_cost_model, argb,
480 cache_bits)) { 504 quality, cache_bits)) {
481 goto Error; 505 goto Error;
482 } 506 }
483 507
484 for (i = 0; i < pix_count; ++i) cost[i] = 1e100; 508 for (i = 0; i < pix_count; ++i) cost[i] = 1e38f;
485 509
486 // We loop one pixel at a time, but store all currently best points to 510 // We loop one pixel at a time, but store all currently best points to
487 // non-processed locations from this point. 511 // non-processed locations from this point.
488 dist_array[0] = 0; 512 dist_array[0] = 0;
513 GetParamsForHashChainFindCopy(quality, xsize, &window_size, &iter_pos,
514 &iter_limit);
489 for (i = 0; i < pix_count; ++i) { 515 for (i = 0; i < pix_count; ++i) {
490 double prev_cost = 0.0; 516 double prev_cost = 0.0;
491 int shortmax; 517 int shortmax;
492 if (i > 0) { 518 if (i > 0) {
493 prev_cost = cost[i - 1]; 519 prev_cost = cost[i - 1];
494 } 520 }
495 for (shortmax = 0; shortmax < 2; ++shortmax) { 521 for (shortmax = 0; shortmax < 2; ++shortmax) {
496 int offset = 0; 522 int offset = 0;
497 int len = 0; 523 int len = 0;
498 if (i < pix_count - 1) { // FindCopy reads pixels at [i] and [i + 1]. 524 if (i < pix_count - 1) { // FindCopy reads pixels at [i] and [i + 1].
499 int maxlen = shortmax ? 2 : MAX_LENGTH; 525 int maxlen = shortmax ? 2 : MAX_LENGTH;
500 if (maxlen > pix_count - i) { 526 if (maxlen > pix_count - i) {
501 maxlen = pix_count - i; 527 maxlen = pix_count - i;
502 } 528 }
503 HashChainFindCopy(hash_chain, quality, i, xsize, argb, maxlen, 529 HashChainFindCopy(hash_chain, i, xsize, argb, maxlen,
530 window_size, iter_pos, iter_limit,
504 &offset, &len); 531 &offset, &len);
505 } 532 }
506 if (len >= MIN_LENGTH) { 533 if (len >= MIN_LENGTH) {
507 const int code = DistanceToPlaneCode(xsize, offset); 534 const int code = DistanceToPlaneCode(xsize, offset);
508 const double distance_cost = 535 const double distance_cost =
509 prev_cost + GetDistanceCost(cost_model, code); 536 prev_cost + GetDistanceCost(cost_model, code);
510 int k; 537 int k;
511 for (k = 1; k < len; ++k) { 538 for (k = 1; k < len; ++k) {
512 const double cost_val = 539 const double cost_val = distance_cost + GetLengthCost(cost_model, k);
513 distance_cost + GetLengthCost(cost_model, k);
514 if (cost[i + k] > cost_val) { 540 if (cost[i + k] > cost_val) {
515 cost[i + k] = cost_val; 541 cost[i + k] = (float)cost_val;
516 dist_array[i + k] = k + 1; 542 dist_array[i + k] = k + 1;
517 } 543 }
518 } 544 }
519 // This if is for speedup only. It roughly doubles the speed, and 545 // This if is for speedup only. It roughly doubles the speed, and
520 // makes compression worse by .1 %. 546 // makes compression worse by .1 %.
521 if (len >= 128 && code < 2) { 547 if (len >= 128 && code <= min_distance_code) {
522 // Long copy for short distances, let's skip the middle 548 // Long copy for short distances, let's skip the middle
523 // lookups for better copies. 549 // lookups for better copies.
524 // 1) insert the hashes. 550 // 1) insert the hashes.
525 if (use_color_cache) { 551 if (use_color_cache) {
526 for (k = 0; k < len; ++k) { 552 for (k = 0; k < len; ++k) {
527 VP8LColorCacheInsert(&hashers, argb[i + k]); 553 VP8LColorCacheInsert(&hashers, argb[i + k]);
528 } 554 }
529 } 555 }
530 // 2) Add to the hash_chain (but cannot add the last pixel) 556 // 2) Add to the hash_chain (but cannot add the last pixel)
531 { 557 {
532 const int last = (len < pix_count - 1 - i) ? len 558 const int last = (len + i < pix_count - 1) ? len + i
533 : pix_count - 1 - i; 559 : pix_count - 1;
534 for (k = 0; k < last; ++k) { 560 for (k = i; k < last; ++k) {
535 HashChainInsert(hash_chain, &argb[i + k], i + k); 561 HashChainInsert(hash_chain, &argb[k], k);
536 } 562 }
537 } 563 }
538 // 3) jump. 564 // 3) jump.
539 i += len - 1; // for loop does ++i, thus -1 here. 565 i += len - 1; // for loop does ++i, thus -1 here.
540 goto next_symbol; 566 goto next_symbol;
541 } 567 }
542 } 568 }
543 } 569 }
544 if (i < pix_count - 1) { 570 if (i < pix_count - 1) {
545 HashChainInsert(hash_chain, &argb[i], i); 571 HashChainInsert(hash_chain, &argb[i], i);
546 } 572 }
547 { 573 {
548 // inserting a literal pixel 574 // inserting a literal pixel
549 double cost_val = prev_cost; 575 double cost_val = prev_cost;
550 if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) { 576 if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
551 const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]); 577 const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]);
552 cost_val += GetCacheCost(cost_model, ix) * mul0; 578 cost_val += GetCacheCost(cost_model, ix) * mul0;
553 } else { 579 } else {
554 cost_val += GetLiteralCost(cost_model, argb[i]) * mul1; 580 cost_val += GetLiteralCost(cost_model, argb[i]) * mul1;
555 } 581 }
556 if (cost[i] > cost_val) { 582 if (cost[i] > cost_val) {
557 cost[i] = cost_val; 583 cost[i] = (float)cost_val;
558 dist_array[i] = 1; // only one is inserted. 584 dist_array[i] = 1; // only one is inserted.
559 } 585 }
560 if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); 586 if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
561 } 587 }
562 next_symbol: ; 588 next_symbol: ;
563 } 589 }
564 // 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
565 // through cheaper means already. 591 // through cheaper means already.
566 ok = 1; 592 ok = 1;
567 Error: 593 Error:
568 if (cc_init) VP8LColorCacheClear(&hashers); 594 if (cc_init) VP8LColorCacheClear(&hashers);
569 HashChainDelete(hash_chain); 595 HashChainDelete(hash_chain);
570 free(cost_model); 596 free(cost_model);
571 free(cost); 597 free(cost);
572 return ok; 598 return ok;
573 } 599 }
574 600
575 static int TraceBackwards(const uint32_t* const dist_array, 601 // We pack the path at the end of *dist_array and return
576 int dist_array_size, 602 // a pointer to this part of the array. Example:
577 uint32_t** const chosen_path, 603 // dist_array = [1x2xx3x2] => packed [1x2x1232], chosen_path = [1232]
578 int* const chosen_path_size) { 604 static void TraceBackwards(uint32_t* const dist_array,
579 int i; 605 int dist_array_size,
580 // Count how many. 606 uint32_t** const chosen_path,
581 int count = 0; 607 int* const chosen_path_size) {
582 for (i = dist_array_size - 1; i >= 0; ) { 608 uint32_t* path = dist_array + dist_array_size;
583 int k = dist_array[i]; 609 uint32_t* cur = dist_array + dist_array_size - 1;
584 assert(k >= 1); 610 while (cur >= dist_array) {
585 ++count; 611 const int k = *cur;
586 i -= k; 612 --path;
613 *path = k;
614 cur -= k;
587 } 615 }
588 // Allocate. 616 *chosen_path = path;
589 *chosen_path_size = count; 617 *chosen_path_size = (int)(dist_array + dist_array_size - path);
590 *chosen_path =
591 (uint32_t*)WebPSafeMalloc((uint64_t)count, sizeof(**chosen_path));
592 if (*chosen_path == NULL) return 0;
593
594 // Write in reverse order.
595 for (i = dist_array_size - 1; i >= 0; ) {
596 int k = dist_array[i];
597 assert(k >= 1);
598 (*chosen_path)[--count] = k;
599 i -= k;
600 }
601 return 1;
602 } 618 }
603 619
604 static int BackwardReferencesHashChainFollowChosenPath( 620 static int BackwardReferencesHashChainFollowChosenPath(
605 int xsize, int ysize, const uint32_t* const argb, int cache_bits, 621 int xsize, int ysize, const uint32_t* const argb,
622 int quality, int cache_bits,
606 const uint32_t* const chosen_path, int chosen_path_size, 623 const uint32_t* const chosen_path, int chosen_path_size,
607 VP8LBackwardRefs* const refs) { 624 VP8LBackwardRefs* const refs) {
608 const int quality = 100;
609 const int pix_count = xsize * ysize; 625 const int pix_count = xsize * ysize;
610 const int use_color_cache = (cache_bits > 0); 626 const int use_color_cache = (cache_bits > 0);
611 int size = 0; 627 int size = 0;
612 int i = 0; 628 int i = 0;
613 int k; 629 int k;
614 int ix; 630 int ix;
615 int ok = 0; 631 int ok = 0;
616 int cc_init = 0; 632 int cc_init = 0;
633 int window_size = WINDOW_SIZE;
634 int iter_pos = 1;
635 int iter_limit = -1;
617 HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain)); 636 HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
618 VP8LColorCache hashers; 637 VP8LColorCache hashers;
619 638
620 if (hash_chain == NULL || !HashChainInit(hash_chain, pix_count)) { 639 if (hash_chain == NULL || !HashChainInit(hash_chain, pix_count)) {
621 goto Error; 640 goto Error;
622 } 641 }
623 if (use_color_cache) { 642 if (use_color_cache) {
624 cc_init = VP8LColorCacheInit(&hashers, cache_bits); 643 cc_init = VP8LColorCacheInit(&hashers, cache_bits);
625 if (!cc_init) goto Error; 644 if (!cc_init) goto Error;
626 } 645 }
627 646
628 refs->size = 0; 647 refs->size = 0;
648 GetParamsForHashChainFindCopy(quality, xsize, &window_size, &iter_pos,
649 &iter_limit);
629 for (ix = 0; ix < chosen_path_size; ++ix, ++size) { 650 for (ix = 0; ix < chosen_path_size; ++ix, ++size) {
630 int offset = 0; 651 int offset = 0;
631 int len = 0; 652 int len = 0;
632 int maxlen = chosen_path[ix]; 653 int maxlen = chosen_path[ix];
633 if (maxlen != 1) { 654 if (maxlen != 1) {
634 HashChainFindCopy(hash_chain, quality, 655 HashChainFindCopy(hash_chain, i, xsize, argb, maxlen,
635 i, xsize, argb, maxlen, &offset, &len); 656 window_size, iter_pos, iter_limit,
657 &offset, &len);
636 assert(len == maxlen); 658 assert(len == maxlen);
637 refs->refs[size] = PixOrCopyCreateCopy(offset, len); 659 refs->refs[size] = PixOrCopyCreateCopy(offset, len);
638 if (use_color_cache) { 660 if (use_color_cache) {
639 for (k = 0; k < len; ++k) { 661 for (k = 0; k < len; ++k) {
640 VP8LColorCacheInsert(&hashers, argb[i + k]); 662 VP8LColorCacheInsert(&hashers, argb[i + k]);
641 } 663 }
642 } 664 }
643 { 665 {
644 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;
645 for (k = 0; k < last; ++k) { 667 for (k = 0; k < last; ++k) {
(...skipping 22 matching lines...) Expand all
668 Error: 690 Error:
669 if (cc_init) VP8LColorCacheClear(&hashers); 691 if (cc_init) VP8LColorCacheClear(&hashers);
670 HashChainDelete(hash_chain); 692 HashChainDelete(hash_chain);
671 return ok; 693 return ok;
672 } 694 }
673 695
674 // Returns 1 on success. 696 // Returns 1 on success.
675 static int BackwardReferencesTraceBackwards(int xsize, int ysize, 697 static int BackwardReferencesTraceBackwards(int xsize, int ysize,
676 int recursive_cost_model, 698 int recursive_cost_model,
677 const uint32_t* const argb, 699 const uint32_t* const argb,
678 int cache_bits, 700 int quality, int cache_bits,
679 VP8LBackwardRefs* const refs) { 701 VP8LBackwardRefs* const refs) {
680 int ok = 0; 702 int ok = 0;
681 const int dist_array_size = xsize * ysize; 703 const int dist_array_size = xsize * ysize;
682 uint32_t* chosen_path = NULL; 704 uint32_t* chosen_path = NULL;
683 int chosen_path_size = 0; 705 int chosen_path_size = 0;
684 uint32_t* dist_array = 706 uint32_t* dist_array =
685 (uint32_t*)WebPSafeMalloc((uint64_t)dist_array_size, sizeof(*dist_array)); 707 (uint32_t*)WebPSafeMalloc((uint64_t)dist_array_size, sizeof(*dist_array));
686 708
687 if (dist_array == NULL) goto Error; 709 if (dist_array == NULL) goto Error;
688 710
689 if (!BackwardReferencesHashChainDistanceOnly( 711 if (!BackwardReferencesHashChainDistanceOnly(
690 xsize, ysize, recursive_cost_model, argb, cache_bits, dist_array)) { 712 xsize, ysize, recursive_cost_model, argb, quality, cache_bits,
713 dist_array)) {
691 goto Error; 714 goto Error;
692 } 715 }
693 if (!TraceBackwards(dist_array, dist_array_size, 716 TraceBackwards(dist_array, dist_array_size, &chosen_path, &chosen_path_size);
694 &chosen_path, &chosen_path_size)) {
695 goto Error;
696 }
697 free(dist_array); // no need to retain this memory any longer
698 dist_array = NULL;
699 if (!BackwardReferencesHashChainFollowChosenPath( 717 if (!BackwardReferencesHashChainFollowChosenPath(
700 xsize, ysize, argb, cache_bits, chosen_path, chosen_path_size, refs)) { 718 xsize, ysize, argb, quality, cache_bits, chosen_path, chosen_path_size,
719 refs)) {
701 goto Error; 720 goto Error;
702 } 721 }
703 ok = 1; 722 ok = 1;
704 Error: 723 Error:
705 free(chosen_path);
706 free(dist_array); 724 free(dist_array);
707 return ok; 725 return ok;
708 } 726 }
709 727
710 static void BackwardReferences2DLocality(int xsize, 728 static void BackwardReferences2DLocality(int xsize,
711 VP8LBackwardRefs* const refs) { 729 VP8LBackwardRefs* const refs) {
712 int i; 730 int i;
713 for (i = 0; i < refs->size; ++i) { 731 for (i = 0; i < refs->size; ++i) {
714 if (PixOrCopyIsCopy(&refs->refs[i])) { 732 if (PixOrCopyIsCopy(&refs->refs[i])) {
715 const int dist = refs->refs[i].argb_or_distance; 733 const int dist = refs->refs[i].argb_or_distance;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
755 // Evaluate RLE coding 773 // Evaluate RLE coding
756 VP8LHistogramCreate(histo, &refs_rle, cache_bits); 774 VP8LHistogramCreate(histo, &refs_rle, cache_bits);
757 bit_cost_rle = VP8LHistogramEstimateBits(histo); 775 bit_cost_rle = VP8LHistogramEstimateBits(histo);
758 // Decide if LZ77 is useful. 776 // Decide if LZ77 is useful.
759 lz77_is_useful = (bit_cost_lz77 < bit_cost_rle); 777 lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
760 free(histo); 778 free(histo);
761 } 779 }
762 780
763 // Choose appropriate backward reference. 781 // Choose appropriate backward reference.
764 if (lz77_is_useful) { 782 if (lz77_is_useful) {
765 // TraceBackwards is costly. Run it for higher qualities. 783 // TraceBackwards is costly. Don't execute it at lower quality (q <= 10).
766 const int try_lz77_trace_backwards = (quality >= 75); 784 const int try_lz77_trace_backwards = (quality > 10);
767 *best = refs_lz77; // default guess: lz77 is better 785 *best = refs_lz77; // default guess: lz77 is better
768 VP8LClearBackwardRefs(&refs_rle); 786 VP8LClearBackwardRefs(&refs_rle);
769 if (try_lz77_trace_backwards) { 787 if (try_lz77_trace_backwards) {
770 const int recursion_level = (num_pix < 320 * 200) ? 1 : 0; 788 const int recursion_level = (num_pix < 320 * 200) ? 1 : 0;
771 VP8LBackwardRefs refs_trace; 789 VP8LBackwardRefs refs_trace;
772 if (!VP8LBackwardRefsAlloc(&refs_trace, num_pix)) { 790 if (!VP8LBackwardRefsAlloc(&refs_trace, num_pix)) {
773 goto End; 791 goto End;
774 } 792 }
775 if (BackwardReferencesTraceBackwards( 793 if (BackwardReferencesTraceBackwards(width, height, recursion_level, argb,
776 width, height, recursion_level, argb, cache_bits, &refs_trace)) { 794 quality, cache_bits, &refs_trace)) {
777 VP8LClearBackwardRefs(&refs_lz77); 795 VP8LClearBackwardRefs(&refs_lz77);
778 *best = refs_trace; 796 *best = refs_trace;
779 } 797 }
780 } 798 }
781 } else { 799 } else {
782 VP8LClearBackwardRefs(&refs_lz77); 800 VP8LClearBackwardRefs(&refs_lz77);
783 *best = refs_rle; 801 *best = refs_rle;
784 } 802 }
785 803
786 if (use_2d_locality) BackwardReferences2DLocality(width, best); 804 if (use_2d_locality) BackwardReferences2DLocality(width, best);
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
865 if (cache_bits == 0 || cur_entropy < lowest_entropy) { 883 if (cache_bits == 0 || cur_entropy < lowest_entropy) {
866 *best_cache_bits = cache_bits; 884 *best_cache_bits = cache_bits;
867 lowest_entropy = cur_entropy; 885 lowest_entropy = cur_entropy;
868 } 886 }
869 } 887 }
870 ok = 1; 888 ok = 1;
871 Error: 889 Error:
872 VP8LClearBackwardRefs(&refs); 890 VP8LClearBackwardRefs(&refs);
873 return ok; 891 return ok;
874 } 892 }
OLDNEW
« no previous file with comments | « third_party/libwebp/enc/backward_references.h ('k') | third_party/libwebp/enc/config.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698