Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libwebp/src/enc/histogram_enc.c
21733 views
1
// Copyright 2012 Google Inc. All Rights Reserved.
2
//
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
5
// tree. An additional intellectual property rights grant can be found
6
// in the file PATENTS. All contributing project authors may
7
// be found in the AUTHORS file in the root of the source tree.
8
// -----------------------------------------------------------------------------
9
//
10
// Author: Jyrki Alakuijala ([email protected])
11
//
12
#ifdef HAVE_CONFIG_H
13
#include "src/webp/config.h"
14
#endif
15
16
#include <assert.h>
17
#include <stdlib.h>
18
#include <string.h>
19
20
#include "src/dsp/lossless.h"
21
#include "src/dsp/lossless_common.h"
22
#include "src/enc/backward_references_enc.h"
23
#include "src/enc/histogram_enc.h"
24
#include "src/enc/vp8i_enc.h"
25
#include "src/utils/utils.h"
26
#include "src/webp/encode.h"
27
#include "src/webp/format_constants.h"
28
#include "src/webp/types.h"
29
30
// Number of partitions for the three dominant (literal, red and blue) symbol
31
// costs.
32
#define NUM_PARTITIONS 4
33
// The size of the bin-hash corresponding to the three dominant costs.
34
#define BIN_SIZE (NUM_PARTITIONS * NUM_PARTITIONS * NUM_PARTITIONS)
35
// Maximum number of histograms allowed in greedy combining algorithm.
36
#define MAX_HISTO_GREEDY 100
37
38
// Enum to meaningfully access the elements of the Histogram arrays.
39
typedef enum {
40
LITERAL = 0,
41
RED,
42
BLUE,
43
ALPHA,
44
DISTANCE
45
} HistogramIndex;
46
47
// Return the size of the histogram for a given cache_bits.
48
static int GetHistogramSize(int cache_bits) {
49
const int literal_size = VP8LHistogramNumCodes(cache_bits);
50
const size_t total_size = sizeof(VP8LHistogram) + sizeof(int) * literal_size;
51
assert(total_size <= (size_t)0x7fffffff);
52
return (int)total_size;
53
}
54
55
static void HistogramStatsClear(VP8LHistogram* const h) {
56
int i;
57
for (i = 0; i < 5; ++i) {
58
h->trivial_symbol[i] = VP8L_NON_TRIVIAL_SYM;
59
// By default, the histogram is assumed to be used.
60
h->is_used[i] = 1;
61
}
62
h->bit_cost = 0;
63
memset(h->costs, 0, sizeof(h->costs));
64
}
65
66
static void HistogramClear(VP8LHistogram* const h) {
67
uint32_t* const literal = h->literal;
68
const int cache_bits = h->palette_code_bits;
69
const int histo_size = GetHistogramSize(cache_bits);
70
memset(h, 0, histo_size);
71
h->palette_code_bits = cache_bits;
72
h->literal = literal;
73
HistogramStatsClear(h);
74
}
75
76
// Swap two histogram pointers.
77
static void HistogramSwap(VP8LHistogram** const h1, VP8LHistogram** const h2) {
78
VP8LHistogram* const tmp = *h1;
79
*h1 = *h2;
80
*h2 = tmp;
81
}
82
83
static void HistogramCopy(const VP8LHistogram* const src,
84
VP8LHistogram* const dst) {
85
uint32_t* const dst_literal = dst->literal;
86
const int dst_cache_bits = dst->palette_code_bits;
87
const int literal_size = VP8LHistogramNumCodes(dst_cache_bits);
88
const int histo_size = GetHistogramSize(dst_cache_bits);
89
assert(src->palette_code_bits == dst_cache_bits);
90
memcpy(dst, src, histo_size);
91
dst->literal = dst_literal;
92
memcpy(dst->literal, src->literal, literal_size * sizeof(*dst->literal));
93
}
94
95
void VP8LFreeHistogram(VP8LHistogram* const h) { WebPSafeFree(h); }
96
97
void VP8LFreeHistogramSet(VP8LHistogramSet* const histograms) {
98
WebPSafeFree(histograms);
99
}
100
101
void VP8LHistogramCreate(VP8LHistogram* const h,
102
const VP8LBackwardRefs* const refs,
103
int palette_code_bits) {
104
if (palette_code_bits >= 0) {
105
h->palette_code_bits = palette_code_bits;
106
}
107
HistogramClear(h);
108
VP8LHistogramStoreRefs(refs, /*distance_modifier=*/NULL,
109
/*distance_modifier_arg0=*/0, h);
110
}
111
112
void VP8LHistogramInit(VP8LHistogram* const h, int palette_code_bits,
113
int init_arrays) {
114
h->palette_code_bits = palette_code_bits;
115
if (init_arrays) {
116
HistogramClear(h);
117
} else {
118
HistogramStatsClear(h);
119
}
120
}
121
122
VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
123
VP8LHistogram* histo = NULL;
124
const int total_size = GetHistogramSize(cache_bits);
125
uint8_t* const memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
126
if (memory == NULL) return NULL;
127
histo = (VP8LHistogram*)memory;
128
// 'literal' won't necessary be aligned.
129
histo->literal = (uint32_t*)(memory + sizeof(VP8LHistogram));
130
VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0);
131
return histo;
132
}
133
134
// Resets the pointers of the histograms to point to the bit buffer in the set.
135
static void HistogramSetResetPointers(VP8LHistogramSet* const set,
136
int cache_bits) {
137
int i;
138
const int histo_size = GetHistogramSize(cache_bits);
139
uint8_t* memory = (uint8_t*) (set->histograms);
140
memory += set->max_size * sizeof(*set->histograms);
141
for (i = 0; i < set->max_size; ++i) {
142
memory = (uint8_t*) WEBP_ALIGN(memory);
143
set->histograms[i] = (VP8LHistogram*) memory;
144
// 'literal' won't necessary be aligned.
145
set->histograms[i]->literal = (uint32_t*)(memory + sizeof(VP8LHistogram));
146
memory += histo_size;
147
}
148
}
149
150
// Returns the total size of the VP8LHistogramSet.
151
static size_t HistogramSetTotalSize(int size, int cache_bits) {
152
const int histo_size = GetHistogramSize(cache_bits);
153
return (sizeof(VP8LHistogramSet) + size * (sizeof(VP8LHistogram*) +
154
histo_size + WEBP_ALIGN_CST));
155
}
156
157
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
158
int i;
159
VP8LHistogramSet* set;
160
const size_t total_size = HistogramSetTotalSize(size, cache_bits);
161
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
162
if (memory == NULL) return NULL;
163
164
set = (VP8LHistogramSet*)memory;
165
memory += sizeof(*set);
166
set->histograms = (VP8LHistogram**)memory;
167
set->max_size = size;
168
set->size = size;
169
HistogramSetResetPointers(set, cache_bits);
170
for (i = 0; i < size; ++i) {
171
VP8LHistogramInit(set->histograms[i], cache_bits, /*init_arrays=*/ 0);
172
}
173
return set;
174
}
175
176
void VP8LHistogramSetClear(VP8LHistogramSet* const set) {
177
int i;
178
const int cache_bits = set->histograms[0]->palette_code_bits;
179
const int size = set->max_size;
180
const size_t total_size = HistogramSetTotalSize(size, cache_bits);
181
uint8_t* memory = (uint8_t*)set;
182
183
memset(memory, 0, total_size);
184
memory += sizeof(*set);
185
set->histograms = (VP8LHistogram**)memory;
186
set->max_size = size;
187
set->size = size;
188
HistogramSetResetPointers(set, cache_bits);
189
for (i = 0; i < size; ++i) {
190
set->histograms[i]->palette_code_bits = cache_bits;
191
}
192
}
193
194
// Removes the histogram 'i' from 'set'.
195
static void HistogramSetRemoveHistogram(VP8LHistogramSet* const set, int i) {
196
set->histograms[i] = set->histograms[set->size - 1];
197
--set->size;
198
assert(set->size > 0);
199
}
200
201
// -----------------------------------------------------------------------------
202
203
static void HistogramAddSinglePixOrCopy(
204
VP8LHistogram* const histo, const PixOrCopy* const v,
205
int (*const distance_modifier)(int, int), int distance_modifier_arg0) {
206
if (PixOrCopyIsLiteral(v)) {
207
++histo->alpha[PixOrCopyLiteral(v, 3)];
208
++histo->red[PixOrCopyLiteral(v, 2)];
209
++histo->literal[PixOrCopyLiteral(v, 1)];
210
++histo->blue[PixOrCopyLiteral(v, 0)];
211
} else if (PixOrCopyIsCacheIdx(v)) {
212
const int literal_ix =
213
NUM_LITERAL_CODES + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
214
assert(histo->palette_code_bits != 0);
215
++histo->literal[literal_ix];
216
} else {
217
int code, extra_bits;
218
VP8LPrefixEncodeBits(PixOrCopyLength(v), &code, &extra_bits);
219
++histo->literal[NUM_LITERAL_CODES + code];
220
if (distance_modifier == NULL) {
221
VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits);
222
} else {
223
VP8LPrefixEncodeBits(
224
distance_modifier(distance_modifier_arg0, PixOrCopyDistance(v)),
225
&code, &extra_bits);
226
}
227
++histo->distance[code];
228
}
229
}
230
231
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
232
int (*const distance_modifier)(int, int),
233
int distance_modifier_arg0,
234
VP8LHistogram* const histo) {
235
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
236
while (VP8LRefsCursorOk(&c)) {
237
HistogramAddSinglePixOrCopy(histo, c.cur_pos, distance_modifier,
238
distance_modifier_arg0);
239
VP8LRefsCursorNext(&c);
240
}
241
}
242
243
// -----------------------------------------------------------------------------
244
// Entropy-related functions.
245
246
static WEBP_INLINE uint64_t BitsEntropyRefine(const VP8LBitEntropy* entropy) {
247
uint64_t mix;
248
if (entropy->nonzeros < 5) {
249
if (entropy->nonzeros <= 1) {
250
return 0;
251
}
252
// Two symbols, they will be 0 and 1 in a Huffman code.
253
// Let's mix in a bit of entropy to favor good clustering when
254
// distributions of these are combined.
255
if (entropy->nonzeros == 2) {
256
return DivRound(99 * ((uint64_t)entropy->sum << LOG_2_PRECISION_BITS) +
257
entropy->entropy,
258
100);
259
}
260
// No matter what the entropy says, we cannot be better than min_limit
261
// with Huffman coding. I am mixing a bit of entropy into the
262
// min_limit since it produces much better (~0.5 %) compression results
263
// perhaps because of better entropy clustering.
264
if (entropy->nonzeros == 3) {
265
mix = 950;
266
} else {
267
mix = 700; // nonzeros == 4.
268
}
269
} else {
270
mix = 627;
271
}
272
273
{
274
uint64_t min_limit = (uint64_t)(2 * entropy->sum - entropy->max_val)
275
<< LOG_2_PRECISION_BITS;
276
min_limit =
277
DivRound(mix * min_limit + (1000 - mix) * entropy->entropy, 1000);
278
return (entropy->entropy < min_limit) ? min_limit : entropy->entropy;
279
}
280
}
281
282
uint64_t VP8LBitsEntropy(const uint32_t* const array, int n) {
283
VP8LBitEntropy entropy;
284
VP8LBitsEntropyUnrefined(array, n, &entropy);
285
286
return BitsEntropyRefine(&entropy);
287
}
288
289
static uint64_t InitialHuffmanCost(void) {
290
// Small bias because Huffman code length is typically not stored in
291
// full length.
292
static const uint64_t kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3;
293
// Subtract a bias of 9.1.
294
return (kHuffmanCodeOfHuffmanCodeSize << LOG_2_PRECISION_BITS) -
295
DivRound(91ll << LOG_2_PRECISION_BITS, 10);
296
}
297
298
// Finalize the Huffman cost based on streak numbers and length type (<3 or >=3)
299
static uint64_t FinalHuffmanCost(const VP8LStreaks* const stats) {
300
// The constants in this function are empirical and got rounded from
301
// their original values in 1/8 when switched to 1/1024.
302
uint64_t retval = InitialHuffmanCost();
303
// Second coefficient: Many zeros in the histogram are covered efficiently
304
// by a run-length encode. Originally 2/8.
305
uint32_t retval_extra = stats->counts[0] * 1600 + 240 * stats->streaks[0][1];
306
// Second coefficient: Constant values are encoded less efficiently, but still
307
// RLE'ed. Originally 6/8.
308
retval_extra += stats->counts[1] * 2640 + 720 * stats->streaks[1][1];
309
// 0s are usually encoded more efficiently than non-0s.
310
// Originally 15/8.
311
retval_extra += 1840 * stats->streaks[0][0];
312
// Originally 26/8.
313
retval_extra += 3360 * stats->streaks[1][0];
314
return retval + ((uint64_t)retval_extra << (LOG_2_PRECISION_BITS - 10));
315
}
316
317
// Get the symbol entropy for the distribution 'population'.
318
// Set 'trivial_sym', if there's only one symbol present in the distribution.
319
static uint64_t PopulationCost(const uint32_t* const population, int length,
320
uint16_t* const trivial_sym,
321
uint8_t* const is_used) {
322
VP8LBitEntropy bit_entropy;
323
VP8LStreaks stats;
324
VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats);
325
if (trivial_sym != NULL) {
326
*trivial_sym = (bit_entropy.nonzeros == 1) ? bit_entropy.nonzero_code
327
: VP8L_NON_TRIVIAL_SYM;
328
}
329
if (is_used != NULL) {
330
// The histogram is used if there is at least one non-zero streak.
331
*is_used = (stats.streaks[1][0] != 0 || stats.streaks[1][1] != 0);
332
}
333
334
return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats);
335
}
336
337
static WEBP_INLINE void GetPopulationInfo(const VP8LHistogram* const histo,
338
HistogramIndex index,
339
const uint32_t** population,
340
int* length) {
341
switch (index) {
342
case LITERAL:
343
*population = histo->literal;
344
*length = VP8LHistogramNumCodes(histo->palette_code_bits);
345
break;
346
case RED:
347
*population = histo->red;
348
*length = NUM_LITERAL_CODES;
349
break;
350
case BLUE:
351
*population = histo->blue;
352
*length = NUM_LITERAL_CODES;
353
break;
354
case ALPHA:
355
*population = histo->alpha;
356
*length = NUM_LITERAL_CODES;
357
break;
358
case DISTANCE:
359
*population = histo->distance;
360
*length = NUM_DISTANCE_CODES;
361
break;
362
}
363
}
364
365
// trivial_at_end is 1 if the two histograms only have one element that is
366
// non-zero: both the zero-th one, or both the last one.
367
// 'index' is the index of the symbol in the histogram (literal, red, blue,
368
// alpha, distance).
369
static WEBP_INLINE uint64_t GetCombinedEntropy(const VP8LHistogram* const h1,
370
const VP8LHistogram* const h2,
371
HistogramIndex index) {
372
const uint32_t* X;
373
const uint32_t* Y;
374
int length;
375
VP8LStreaks stats;
376
VP8LBitEntropy bit_entropy;
377
const int is_h1_used = h1->is_used[index];
378
const int is_h2_used = h2->is_used[index];
379
const int is_trivial = h1->trivial_symbol[index] != VP8L_NON_TRIVIAL_SYM &&
380
h1->trivial_symbol[index] == h2->trivial_symbol[index];
381
382
if (is_trivial || !is_h1_used || !is_h2_used) {
383
if (is_h1_used) return h1->costs[index];
384
return h2->costs[index];
385
}
386
assert(is_h1_used && is_h2_used);
387
388
GetPopulationInfo(h1, index, &X, &length);
389
GetPopulationInfo(h2, index, &Y, &length);
390
VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats);
391
return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats);
392
}
393
394
// Estimates the Entropy + Huffman + other block overhead size cost.
395
uint64_t VP8LHistogramEstimateBits(const VP8LHistogram* const h) {
396
int i;
397
uint64_t cost = 0;
398
for (i = 0; i < 5; ++i) {
399
int length;
400
const uint32_t* population;
401
GetPopulationInfo(h, (HistogramIndex)i, &population, &length);
402
cost += PopulationCost(population, length, /*trivial_sym=*/NULL,
403
/*is_used=*/NULL);
404
}
405
cost += ((uint64_t)(VP8LExtraCost(h->literal + NUM_LITERAL_CODES,
406
NUM_LENGTH_CODES) +
407
VP8LExtraCost(h->distance, NUM_DISTANCE_CODES))
408
<< LOG_2_PRECISION_BITS);
409
return cost;
410
}
411
412
// -----------------------------------------------------------------------------
413
// Various histogram combine/cost-eval functions
414
415
// Set a + b in b, saturating at WEBP_INT64_MAX.
416
static WEBP_INLINE void SaturateAdd(uint64_t a, int64_t* b) {
417
if (*b < 0 || (int64_t)a <= WEBP_INT64_MAX - *b) {
418
*b += (int64_t)a;
419
} else {
420
*b = WEBP_INT64_MAX;
421
}
422
}
423
424
// Returns 1 if the cost of the combined histogram is less than the threshold.
425
// Otherwise returns 0 and the cost is invalid due to early bail-out.
426
WEBP_NODISCARD static int GetCombinedHistogramEntropy(
427
const VP8LHistogram* const a, const VP8LHistogram* const b,
428
int64_t cost_threshold_in, uint64_t* cost, uint64_t costs[5]) {
429
int i;
430
const uint64_t cost_threshold = (uint64_t)cost_threshold_in;
431
assert(a->palette_code_bits == b->palette_code_bits);
432
if (cost_threshold_in <= 0) return 0;
433
*cost = 0;
434
435
// No need to add the extra cost for length and distance as it is a constant
436
// that does not influence the histograms.
437
for (i = 0; i < 5; ++i) {
438
costs[i] = GetCombinedEntropy(a, b, (HistogramIndex)i);
439
*cost += costs[i];
440
if (*cost >= cost_threshold) return 0;
441
}
442
443
return 1;
444
}
445
446
static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const h1,
447
const VP8LHistogram* const h2,
448
VP8LHistogram* const hout) {
449
int i;
450
assert(h1->palette_code_bits == h2->palette_code_bits);
451
452
for (i = 0; i < 5; ++i) {
453
int length;
454
const uint32_t *p1, *p2, *pout_const;
455
uint32_t* pout;
456
GetPopulationInfo(h1, (HistogramIndex)i, &p1, &length);
457
GetPopulationInfo(h2, (HistogramIndex)i, &p2, &length);
458
GetPopulationInfo(hout, (HistogramIndex)i, &pout_const, &length);
459
pout = (uint32_t*)pout_const;
460
if (h2 == hout) {
461
if (h1->is_used[i]) {
462
if (hout->is_used[i]) {
463
VP8LAddVectorEq(p1, pout, length);
464
} else {
465
memcpy(pout, p1, length * sizeof(pout[0]));
466
}
467
}
468
} else {
469
if (h1->is_used[i]) {
470
if (h2->is_used[i]) {
471
VP8LAddVector(p1, p2, pout, length);
472
} else {
473
memcpy(pout, p1, length * sizeof(pout[0]));
474
}
475
} else if (h2->is_used[i]) {
476
memcpy(pout, p2, length * sizeof(pout[0]));
477
} else {
478
memset(pout, 0, length * sizeof(pout[0]));
479
}
480
}
481
}
482
483
for (i = 0; i < 5; ++i) {
484
hout->trivial_symbol[i] = h1->trivial_symbol[i] == h2->trivial_symbol[i]
485
? h1->trivial_symbol[i]
486
: VP8L_NON_TRIVIAL_SYM;
487
hout->is_used[i] = h1->is_used[i] || h2->is_used[i];
488
}
489
}
490
491
static void UpdateHistogramCost(uint64_t bit_cost, uint64_t costs[5],
492
VP8LHistogram* const h) {
493
int i;
494
h->bit_cost = bit_cost;
495
for (i = 0; i < 5; ++i) {
496
h->costs[i] = costs[i];
497
}
498
}
499
500
// Performs out = a + b, computing the cost C(a+b) - C(a) - C(b) while comparing
501
// to the threshold value 'cost_threshold'. The score returned is
502
// Score = C(a+b) - C(a) - C(b), where C(a) + C(b) is known and fixed.
503
// Since the previous score passed is 'cost_threshold', we only need to compare
504
// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out
505
// early.
506
// Returns 1 if the cost is less than the threshold.
507
// Otherwise returns 0 and the cost is invalid due to early bail-out.
508
WEBP_NODISCARD static int HistogramAddEval(const VP8LHistogram* const a,
509
const VP8LHistogram* const b,
510
VP8LHistogram* const out,
511
int64_t cost_threshold) {
512
const uint64_t sum_cost = a->bit_cost + b->bit_cost;
513
uint64_t bit_cost, costs[5];
514
SaturateAdd(sum_cost, &cost_threshold);
515
if (!GetCombinedHistogramEntropy(a, b, cost_threshold, &bit_cost, costs)) {
516
return 0;
517
}
518
519
HistogramAdd(a, b, out);
520
UpdateHistogramCost(bit_cost, costs, out);
521
return 1;
522
}
523
524
// Same as HistogramAddEval(), except that the resulting histogram
525
// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit
526
// the term C(b) which is constant over all the evaluations.
527
// Returns 1 if the cost is less than the threshold.
528
// Otherwise returns 0 and the cost is invalid due to early bail-out.
529
WEBP_NODISCARD static int HistogramAddThresh(const VP8LHistogram* const a,
530
const VP8LHistogram* const b,
531
int64_t cost_threshold,
532
int64_t* cost_out) {
533
uint64_t cost, costs[5];
534
assert(a != NULL && b != NULL);
535
SaturateAdd(a->bit_cost, &cost_threshold);
536
if (!GetCombinedHistogramEntropy(a, b, cost_threshold, &cost, costs)) {
537
return 0;
538
}
539
540
*cost_out = (int64_t)cost - (int64_t)a->bit_cost;
541
return 1;
542
}
543
544
// -----------------------------------------------------------------------------
545
546
// The structure to keep track of cost range for the three dominant entropy
547
// symbols.
548
typedef struct {
549
uint64_t literal_max;
550
uint64_t literal_min;
551
uint64_t red_max;
552
uint64_t red_min;
553
uint64_t blue_max;
554
uint64_t blue_min;
555
} DominantCostRange;
556
557
static void DominantCostRangeInit(DominantCostRange* const c) {
558
c->literal_max = 0;
559
c->literal_min = WEBP_UINT64_MAX;
560
c->red_max = 0;
561
c->red_min = WEBP_UINT64_MAX;
562
c->blue_max = 0;
563
c->blue_min = WEBP_UINT64_MAX;
564
}
565
566
static void UpdateDominantCostRange(
567
const VP8LHistogram* const h, DominantCostRange* const c) {
568
if (c->literal_max < h->costs[LITERAL]) c->literal_max = h->costs[LITERAL];
569
if (c->literal_min > h->costs[LITERAL]) c->literal_min = h->costs[LITERAL];
570
if (c->red_max < h->costs[RED]) c->red_max = h->costs[RED];
571
if (c->red_min > h->costs[RED]) c->red_min = h->costs[RED];
572
if (c->blue_max < h->costs[BLUE]) c->blue_max = h->costs[BLUE];
573
if (c->blue_min > h->costs[BLUE]) c->blue_min = h->costs[BLUE];
574
}
575
576
static void ComputeHistogramCost(VP8LHistogram* const h) {
577
int i;
578
// No need to add the extra cost for length and distance as it is a constant
579
// that does not influence the histograms.
580
for (i = 0; i < 5; ++i) {
581
const uint32_t* population;
582
int length;
583
GetPopulationInfo(h, i, &population, &length);
584
h->costs[i] = PopulationCost(population, length, &h->trivial_symbol[i],
585
&h->is_used[i]);
586
}
587
h->bit_cost = h->costs[LITERAL] + h->costs[RED] + h->costs[BLUE] +
588
h->costs[ALPHA] + h->costs[DISTANCE];
589
}
590
591
static int GetBinIdForEntropy(uint64_t min, uint64_t max, uint64_t val) {
592
const uint64_t range = max - min;
593
if (range > 0) {
594
const uint64_t delta = val - min;
595
return (int)((NUM_PARTITIONS - 1e-6) * delta / range);
596
} else {
597
return 0;
598
}
599
}
600
601
static int GetHistoBinIndex(const VP8LHistogram* const h,
602
const DominantCostRange* const c, int low_effort) {
603
int bin_id =
604
GetBinIdForEntropy(c->literal_min, c->literal_max, h->costs[LITERAL]);
605
assert(bin_id < NUM_PARTITIONS);
606
if (!low_effort) {
607
bin_id = bin_id * NUM_PARTITIONS +
608
GetBinIdForEntropy(c->red_min, c->red_max, h->costs[RED]);
609
bin_id = bin_id * NUM_PARTITIONS +
610
GetBinIdForEntropy(c->blue_min, c->blue_max, h->costs[BLUE]);
611
assert(bin_id < BIN_SIZE);
612
}
613
return bin_id;
614
}
615
616
// Construct the histograms from backward references.
617
static void HistogramBuild(
618
int xsize, int histo_bits, const VP8LBackwardRefs* const backward_refs,
619
VP8LHistogramSet* const image_histo) {
620
int x = 0, y = 0;
621
const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits);
622
VP8LHistogram** const histograms = image_histo->histograms;
623
VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs);
624
assert(histo_bits > 0);
625
VP8LHistogramSetClear(image_histo);
626
while (VP8LRefsCursorOk(&c)) {
627
const PixOrCopy* const v = c.cur_pos;
628
const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
629
HistogramAddSinglePixOrCopy(histograms[ix], v, NULL, 0);
630
x += PixOrCopyLength(v);
631
while (x >= xsize) {
632
x -= xsize;
633
++y;
634
}
635
VP8LRefsCursorNext(&c);
636
}
637
}
638
639
// Copies the histograms and computes its bit_cost.
640
static void HistogramCopyAndAnalyze(VP8LHistogramSet* const orig_histo,
641
VP8LHistogramSet* const image_histo) {
642
int i;
643
VP8LHistogram** const orig_histograms = orig_histo->histograms;
644
VP8LHistogram** const histograms = image_histo->histograms;
645
assert(image_histo->max_size == orig_histo->max_size);
646
image_histo->size = 0;
647
for (i = 0; i < orig_histo->max_size; ++i) {
648
VP8LHistogram* const histo = orig_histograms[i];
649
ComputeHistogramCost(histo);
650
651
// Skip the histogram if it is completely empty, which can happen for tiles
652
// with no information (when they are skipped because of LZ77).
653
if (!histo->is_used[LITERAL] && !histo->is_used[RED] &&
654
!histo->is_used[BLUE] && !histo->is_used[ALPHA] &&
655
!histo->is_used[DISTANCE]) {
656
// The first histogram is always used.
657
assert(i > 0);
658
orig_histograms[i] = NULL;
659
} else {
660
// Copy histograms from orig_histo[] to image_histo[].
661
HistogramCopy(histo, histograms[image_histo->size]);
662
++image_histo->size;
663
}
664
}
665
}
666
667
// Partition histograms to different entropy bins for three dominant (literal,
668
// red and blue) symbol costs and compute the histogram aggregate bit_cost.
669
static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
670
int low_effort) {
671
int i;
672
VP8LHistogram** const histograms = image_histo->histograms;
673
const int histo_size = image_histo->size;
674
DominantCostRange cost_range;
675
DominantCostRangeInit(&cost_range);
676
677
// Analyze the dominant (literal, red and blue) entropy costs.
678
for (i = 0; i < histo_size; ++i) {
679
UpdateDominantCostRange(histograms[i], &cost_range);
680
}
681
682
// bin-hash histograms on three of the dominant (literal, red and blue)
683
// symbol costs and store the resulting bin_id for each histogram.
684
for (i = 0; i < histo_size; ++i) {
685
histograms[i]->bin_id =
686
GetHistoBinIndex(histograms[i], &cost_range, low_effort);
687
}
688
}
689
690
// Merges some histograms with same bin_id together if it's advantageous.
691
// Sets the remaining histograms to NULL.
692
// 'combine_cost_factor' has to be divided by 100.
693
static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
694
VP8LHistogram* cur_combo, int num_bins,
695
int32_t combine_cost_factor,
696
int low_effort) {
697
VP8LHistogram** const histograms = image_histo->histograms;
698
int idx;
699
struct {
700
int16_t first; // position of the histogram that accumulates all
701
// histograms with the same bin_id
702
uint16_t num_combine_failures; // number of combine failures per bin_id
703
} bin_info[BIN_SIZE];
704
705
assert(num_bins <= BIN_SIZE);
706
for (idx = 0; idx < num_bins; ++idx) {
707
bin_info[idx].first = -1;
708
bin_info[idx].num_combine_failures = 0;
709
}
710
711
for (idx = 0; idx < image_histo->size;) {
712
const int bin_id = histograms[idx]->bin_id;
713
const int first = bin_info[bin_id].first;
714
if (first == -1) {
715
bin_info[bin_id].first = idx;
716
++idx;
717
} else if (low_effort) {
718
HistogramAdd(histograms[idx], histograms[first], histograms[first]);
719
HistogramSetRemoveHistogram(image_histo, idx);
720
} else {
721
// try to merge #idx into #first (both share the same bin_id)
722
const uint64_t bit_cost = histograms[idx]->bit_cost;
723
const int64_t bit_cost_thresh =
724
-DivRound((int64_t)bit_cost * combine_cost_factor, 100);
725
if (HistogramAddEval(histograms[first], histograms[idx], cur_combo,
726
bit_cost_thresh)) {
727
const int max_combine_failures = 32;
728
// Try to merge two histograms only if the combo is a trivial one or
729
// the two candidate histograms are already non-trivial.
730
// For some images, 'try_combine' turns out to be false for a lot of
731
// histogram pairs. In that case, we fallback to combining
732
// histograms as usual to avoid increasing the header size.
733
int try_combine =
734
cur_combo->trivial_symbol[RED] != VP8L_NON_TRIVIAL_SYM &&
735
cur_combo->trivial_symbol[BLUE] != VP8L_NON_TRIVIAL_SYM &&
736
cur_combo->trivial_symbol[ALPHA] != VP8L_NON_TRIVIAL_SYM;
737
if (!try_combine) {
738
try_combine =
739
histograms[idx]->trivial_symbol[RED] == VP8L_NON_TRIVIAL_SYM ||
740
histograms[idx]->trivial_symbol[BLUE] == VP8L_NON_TRIVIAL_SYM ||
741
histograms[idx]->trivial_symbol[ALPHA] == VP8L_NON_TRIVIAL_SYM;
742
try_combine &=
743
histograms[first]->trivial_symbol[RED] == VP8L_NON_TRIVIAL_SYM ||
744
histograms[first]->trivial_symbol[BLUE] == VP8L_NON_TRIVIAL_SYM ||
745
histograms[first]->trivial_symbol[ALPHA] == VP8L_NON_TRIVIAL_SYM;
746
}
747
if (try_combine ||
748
bin_info[bin_id].num_combine_failures >= max_combine_failures) {
749
// move the (better) merged histogram to its final slot
750
HistogramSwap(&cur_combo, &histograms[first]);
751
HistogramSetRemoveHistogram(image_histo, idx);
752
} else {
753
++bin_info[bin_id].num_combine_failures;
754
++idx;
755
}
756
} else {
757
++idx;
758
}
759
}
760
}
761
if (low_effort) {
762
// for low_effort case, update the final cost when everything is merged
763
for (idx = 0; idx < image_histo->size; ++idx) {
764
ComputeHistogramCost(histograms[idx]);
765
}
766
}
767
}
768
769
// Implement a Lehmer random number generator with a multiplicative constant of
770
// 48271 and a modulo constant of 2^31 - 1.
771
static uint32_t MyRand(uint32_t* const seed) {
772
*seed = (uint32_t)(((uint64_t)(*seed) * 48271u) % 2147483647u);
773
assert(*seed > 0);
774
return *seed;
775
}
776
777
// -----------------------------------------------------------------------------
778
// Histogram pairs priority queue
779
780
// Pair of histograms. Negative idx1 value means that pair is out-of-date.
781
typedef struct {
782
int idx1;
783
int idx2;
784
int64_t cost_diff;
785
uint64_t cost_combo;
786
uint64_t costs[5];
787
} HistogramPair;
788
789
typedef struct {
790
HistogramPair* queue;
791
int size;
792
int max_size;
793
} HistoQueue;
794
795
static int HistoQueueInit(HistoQueue* const histo_queue, const int max_size) {
796
histo_queue->size = 0;
797
histo_queue->max_size = max_size;
798
// We allocate max_size + 1 because the last element at index "size" is
799
// used as temporary data (and it could be up to max_size).
800
histo_queue->queue = (HistogramPair*)WebPSafeMalloc(
801
histo_queue->max_size + 1, sizeof(*histo_queue->queue));
802
return histo_queue->queue != NULL;
803
}
804
805
static void HistoQueueClear(HistoQueue* const histo_queue) {
806
assert(histo_queue != NULL);
807
WebPSafeFree(histo_queue->queue);
808
histo_queue->size = 0;
809
histo_queue->max_size = 0;
810
}
811
812
// Pop a specific pair in the queue by replacing it with the last one
813
// and shrinking the queue.
814
static void HistoQueuePopPair(HistoQueue* const histo_queue,
815
HistogramPair* const pair) {
816
assert(pair >= histo_queue->queue &&
817
pair < (histo_queue->queue + histo_queue->size));
818
assert(histo_queue->size > 0);
819
*pair = histo_queue->queue[histo_queue->size - 1];
820
--histo_queue->size;
821
}
822
823
// Check whether a pair in the queue should be updated as head or not.
824
static void HistoQueueUpdateHead(HistoQueue* const histo_queue,
825
HistogramPair* const pair) {
826
assert(pair->cost_diff < 0);
827
assert(pair >= histo_queue->queue &&
828
pair < (histo_queue->queue + histo_queue->size));
829
assert(histo_queue->size > 0);
830
if (pair->cost_diff < histo_queue->queue[0].cost_diff) {
831
// Replace the best pair.
832
const HistogramPair tmp = histo_queue->queue[0];
833
histo_queue->queue[0] = *pair;
834
*pair = tmp;
835
}
836
}
837
838
// Replaces the bad_id with good_id in the pair.
839
static void HistoQueueFixPair(int bad_id, int good_id,
840
HistogramPair* const pair) {
841
if (pair->idx1 == bad_id) pair->idx1 = good_id;
842
if (pair->idx2 == bad_id) pair->idx2 = good_id;
843
if (pair->idx1 > pair->idx2) {
844
const int tmp = pair->idx1;
845
pair->idx1 = pair->idx2;
846
pair->idx2 = tmp;
847
}
848
}
849
850
// Update the cost diff and combo of a pair of histograms. This needs to be
851
// called when the histograms have been merged with a third one.
852
// Returns 1 if the cost diff is less than the threshold.
853
// Otherwise returns 0 and the cost is invalid due to early bail-out.
854
WEBP_NODISCARD static int HistoQueueUpdatePair(const VP8LHistogram* const h1,
855
const VP8LHistogram* const h2,
856
int64_t cost_threshold,
857
HistogramPair* const pair) {
858
const int64_t sum_cost = h1->bit_cost + h2->bit_cost;
859
SaturateAdd(sum_cost, &cost_threshold);
860
if (!GetCombinedHistogramEntropy(h1, h2, cost_threshold, &pair->cost_combo,
861
pair->costs)) {
862
return 0;
863
}
864
pair->cost_diff = (int64_t)pair->cost_combo - sum_cost;
865
return 1;
866
}
867
868
// Create a pair from indices "idx1" and "idx2" provided its cost
869
// is inferior to "threshold", a negative entropy.
870
// It returns the cost of the pair, or 0 if it superior to threshold.
871
static int64_t HistoQueuePush(HistoQueue* const histo_queue,
872
VP8LHistogram** const histograms, int idx1,
873
int idx2, int64_t threshold) {
874
const VP8LHistogram* h1;
875
const VP8LHistogram* h2;
876
HistogramPair pair;
877
878
// Stop here if the queue is full.
879
if (histo_queue->size == histo_queue->max_size) return 0;
880
assert(threshold <= 0);
881
if (idx1 > idx2) {
882
const int tmp = idx2;
883
idx2 = idx1;
884
idx1 = tmp;
885
}
886
pair.idx1 = idx1;
887
pair.idx2 = idx2;
888
h1 = histograms[idx1];
889
h2 = histograms[idx2];
890
891
// Do not even consider the pair if it does not improve the entropy.
892
if (!HistoQueueUpdatePair(h1, h2, threshold, &pair)) return 0;
893
894
histo_queue->queue[histo_queue->size++] = pair;
895
HistoQueueUpdateHead(histo_queue, &histo_queue->queue[histo_queue->size - 1]);
896
897
return pair.cost_diff;
898
}
899
900
// -----------------------------------------------------------------------------
901
902
// Combines histograms by continuously choosing the one with the highest cost
903
// reduction.
904
static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) {
905
int ok = 0;
906
const int image_histo_size = image_histo->size;
907
int i, j;
908
VP8LHistogram** const histograms = image_histo->histograms;
909
// Priority queue of histogram pairs.
910
HistoQueue histo_queue;
911
912
// image_histo_size^2 for the queue size is safe. If you look at
913
// HistogramCombineGreedy, and imagine that UpdateQueueFront always pushes
914
// data to the queue, you insert at most:
915
// - image_histo_size*(image_histo_size-1)/2 (the first two for loops)
916
// - image_histo_size - 1 in the last for loop at the first iteration of
917
// the while loop, image_histo_size - 2 at the second iteration ...
918
// therefore image_histo_size*(image_histo_size-1)/2 overall too
919
if (!HistoQueueInit(&histo_queue, image_histo_size * image_histo_size)) {
920
goto End;
921
}
922
923
// Initialize the queue.
924
for (i = 0; i < image_histo_size; ++i) {
925
for (j = i + 1; j < image_histo_size; ++j) {
926
HistoQueuePush(&histo_queue, histograms, i, j, 0);
927
}
928
}
929
930
while (histo_queue.size > 0) {
931
const int idx1 = histo_queue.queue[0].idx1;
932
const int idx2 = histo_queue.queue[0].idx2;
933
HistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]);
934
UpdateHistogramCost(histo_queue.queue[0].cost_combo,
935
histo_queue.queue[0].costs, histograms[idx1]);
936
937
// Remove merged histogram.
938
HistogramSetRemoveHistogram(image_histo, idx2);
939
940
// Remove pairs intersecting the just combined best pair.
941
for (i = 0; i < histo_queue.size;) {
942
HistogramPair* const p = histo_queue.queue + i;
943
if (p->idx1 == idx1 || p->idx2 == idx1 ||
944
p->idx1 == idx2 || p->idx2 == idx2) {
945
HistoQueuePopPair(&histo_queue, p);
946
} else {
947
HistoQueueFixPair(image_histo->size, idx2, p);
948
HistoQueueUpdateHead(&histo_queue, p);
949
++i;
950
}
951
}
952
953
// Push new pairs formed with combined histogram to the queue.
954
for (i = 0; i < image_histo->size; ++i) {
955
if (i == idx1) continue;
956
HistoQueuePush(&histo_queue, image_histo->histograms, idx1, i, 0);
957
}
958
}
959
960
ok = 1;
961
962
End:
963
HistoQueueClear(&histo_queue);
964
return ok;
965
}
966
967
// Perform histogram aggregation using a stochastic approach.
968
// 'do_greedy' is set to 1 if a greedy approach needs to be performed
969
// afterwards, 0 otherwise.
970
static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
971
int min_cluster_size,
972
int* const do_greedy) {
973
int j, iter;
974
uint32_t seed = 1;
975
int tries_with_no_success = 0;
976
const int outer_iters = image_histo->size;
977
const int num_tries_no_success = outer_iters / 2;
978
VP8LHistogram** const histograms = image_histo->histograms;
979
// Priority queue of histogram pairs. Its size of 'kHistoQueueSize'
980
// impacts the quality of the compression and the speed: the smaller the
981
// faster but the worse for the compression.
982
HistoQueue histo_queue;
983
const int kHistoQueueSize = 9;
984
int ok = 0;
985
986
if (image_histo->size < min_cluster_size) {
987
*do_greedy = 1;
988
return 1;
989
}
990
991
if (!HistoQueueInit(&histo_queue, kHistoQueueSize)) goto End;
992
993
// Collapse similar histograms in 'image_histo'.
994
for (iter = 0; iter < outer_iters && image_histo->size >= min_cluster_size &&
995
++tries_with_no_success < num_tries_no_success;
996
++iter) {
997
int64_t best_cost =
998
(histo_queue.size == 0) ? 0 : histo_queue.queue[0].cost_diff;
999
int best_idx1 = -1, best_idx2 = 1;
1000
const uint32_t rand_range = (image_histo->size - 1) * (image_histo->size);
1001
// (image_histo->size) / 2 was chosen empirically. Less means faster but
1002
// worse compression.
1003
const int num_tries = (image_histo->size) / 2;
1004
1005
// Pick random samples.
1006
for (j = 0; image_histo->size >= 2 && j < num_tries; ++j) {
1007
int64_t curr_cost;
1008
// Choose two different histograms at random and try to combine them.
1009
const uint32_t tmp = MyRand(&seed) % rand_range;
1010
uint32_t idx1 = tmp / (image_histo->size - 1);
1011
uint32_t idx2 = tmp % (image_histo->size - 1);
1012
if (idx2 >= idx1) ++idx2;
1013
1014
// Calculate cost reduction on combination.
1015
curr_cost =
1016
HistoQueuePush(&histo_queue, histograms, idx1, idx2, best_cost);
1017
if (curr_cost < 0) { // found a better pair?
1018
best_cost = curr_cost;
1019
// Empty the queue if we reached full capacity.
1020
if (histo_queue.size == histo_queue.max_size) break;
1021
}
1022
}
1023
if (histo_queue.size == 0) continue;
1024
1025
// Get the best histograms.
1026
best_idx1 = histo_queue.queue[0].idx1;
1027
best_idx2 = histo_queue.queue[0].idx2;
1028
assert(best_idx1 < best_idx2);
1029
// Merge the histograms and remove best_idx2 from the queue.
1030
HistogramAdd(histograms[best_idx2], histograms[best_idx1],
1031
histograms[best_idx1]);
1032
UpdateHistogramCost(histo_queue.queue[0].cost_combo,
1033
histo_queue.queue[0].costs, histograms[best_idx1]);
1034
HistogramSetRemoveHistogram(image_histo, best_idx2);
1035
// Parse the queue and update each pair that deals with best_idx1,
1036
// best_idx2 or image_histo_size.
1037
for (j = 0; j < histo_queue.size;) {
1038
HistogramPair* const p = histo_queue.queue + j;
1039
const int is_idx1_best = p->idx1 == best_idx1 || p->idx1 == best_idx2;
1040
const int is_idx2_best = p->idx2 == best_idx1 || p->idx2 == best_idx2;
1041
// The front pair could have been duplicated by a random pick so
1042
// check for it all the time nevertheless.
1043
if (is_idx1_best && is_idx2_best) {
1044
HistoQueuePopPair(&histo_queue, p);
1045
continue;
1046
}
1047
// Any pair containing one of the two best indices should only refer to
1048
// best_idx1. Its cost should also be updated.
1049
if (is_idx1_best || is_idx2_best) {
1050
HistoQueueFixPair(best_idx2, best_idx1, p);
1051
// Re-evaluate the cost of an updated pair.
1052
if (!HistoQueueUpdatePair(histograms[p->idx1], histograms[p->idx2], 0,
1053
p)) {
1054
HistoQueuePopPair(&histo_queue, p);
1055
continue;
1056
}
1057
}
1058
HistoQueueFixPair(image_histo->size, best_idx2, p);
1059
HistoQueueUpdateHead(&histo_queue, p);
1060
++j;
1061
}
1062
tries_with_no_success = 0;
1063
}
1064
*do_greedy = (image_histo->size <= min_cluster_size);
1065
ok = 1;
1066
1067
End:
1068
HistoQueueClear(&histo_queue);
1069
return ok;
1070
}
1071
1072
// -----------------------------------------------------------------------------
1073
// Histogram refinement
1074
1075
// Find the best 'out' histogram for each of the 'in' histograms.
1076
// At call-time, 'out' contains the histograms of the clusters.
1077
// Note: we assume that out[]->bit_cost is already up-to-date.
1078
static void HistogramRemap(const VP8LHistogramSet* const in,
1079
VP8LHistogramSet* const out,
1080
uint32_t* const symbols) {
1081
int i;
1082
VP8LHistogram** const in_histo = in->histograms;
1083
VP8LHistogram** const out_histo = out->histograms;
1084
const int in_size = out->max_size;
1085
const int out_size = out->size;
1086
if (out_size > 1) {
1087
for (i = 0; i < in_size; ++i) {
1088
int best_out = 0;
1089
int64_t best_bits = WEBP_INT64_MAX;
1090
int k;
1091
if (in_histo[i] == NULL) {
1092
// Arbitrarily set to the previous value if unused to help future LZ77.
1093
symbols[i] = symbols[i - 1];
1094
continue;
1095
}
1096
for (k = 0; k < out_size; ++k) {
1097
int64_t cur_bits;
1098
if (HistogramAddThresh(out_histo[k], in_histo[i], best_bits,
1099
&cur_bits)) {
1100
best_bits = cur_bits;
1101
best_out = k;
1102
}
1103
}
1104
symbols[i] = best_out;
1105
}
1106
} else {
1107
assert(out_size == 1);
1108
for (i = 0; i < in_size; ++i) {
1109
symbols[i] = 0;
1110
}
1111
}
1112
1113
// Recompute each out based on raw and symbols.
1114
VP8LHistogramSetClear(out);
1115
out->size = out_size;
1116
1117
for (i = 0; i < in_size; ++i) {
1118
int idx;
1119
if (in_histo[i] == NULL) continue;
1120
idx = symbols[i];
1121
HistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]);
1122
}
1123
}
1124
1125
static int32_t GetCombineCostFactor(int histo_size, int quality) {
1126
int32_t combine_cost_factor = 16;
1127
if (quality < 90) {
1128
if (histo_size > 256) combine_cost_factor /= 2;
1129
if (histo_size > 512) combine_cost_factor /= 2;
1130
if (histo_size > 1024) combine_cost_factor /= 2;
1131
if (quality <= 50) combine_cost_factor /= 2;
1132
}
1133
return combine_cost_factor;
1134
}
1135
1136
int VP8LGetHistoImageSymbols(int xsize, int ysize,
1137
const VP8LBackwardRefs* const refs, int quality,
1138
int low_effort, int histogram_bits, int cache_bits,
1139
VP8LHistogramSet* const image_histo,
1140
VP8LHistogram* const tmp_histo,
1141
uint32_t* const histogram_symbols,
1142
const WebPPicture* const pic, int percent_range,
1143
int* const percent) {
1144
const int histo_xsize =
1145
histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1;
1146
const int histo_ysize =
1147
histogram_bits ? VP8LSubSampleSize(ysize, histogram_bits) : 1;
1148
const int image_histo_raw_size = histo_xsize * histo_ysize;
1149
VP8LHistogramSet* const orig_histo =
1150
VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits);
1151
// Don't attempt linear bin-partition heuristic for
1152
// histograms of small sizes (as bin_map will be very sparse) and
1153
// maximum quality q==100 (to preserve the compression gains at that level).
1154
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
1155
int entropy_combine;
1156
if (orig_histo == NULL) {
1157
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
1158
goto Error;
1159
}
1160
1161
// Construct the histograms from backward references.
1162
HistogramBuild(xsize, histogram_bits, refs, orig_histo);
1163
HistogramCopyAndAnalyze(orig_histo, image_histo);
1164
entropy_combine =
1165
(image_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
1166
1167
if (entropy_combine) {
1168
const int32_t combine_cost_factor =
1169
GetCombineCostFactor(image_histo_raw_size, quality);
1170
1171
HistogramAnalyzeEntropyBin(image_histo, low_effort);
1172
// Collapse histograms with similar entropy.
1173
HistogramCombineEntropyBin(image_histo, tmp_histo, entropy_combine_num_bins,
1174
combine_cost_factor, low_effort);
1175
}
1176
1177
// Don't combine the histograms using stochastic and greedy heuristics for
1178
// low-effort compression mode.
1179
if (!low_effort || !entropy_combine) {
1180
// cubic ramp between 1 and MAX_HISTO_GREEDY:
1181
const int threshold_size =
1182
(int)(1 + DivRound(quality * quality * quality * (MAX_HISTO_GREEDY - 1),
1183
100 * 100 * 100));
1184
int do_greedy;
1185
if (!HistogramCombineStochastic(image_histo, threshold_size, &do_greedy)) {
1186
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
1187
goto Error;
1188
}
1189
if (do_greedy) {
1190
if (!HistogramCombineGreedy(image_histo)) {
1191
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
1192
goto Error;
1193
}
1194
}
1195
}
1196
1197
// Find the optimal map from original histograms to the final ones.
1198
HistogramRemap(orig_histo, image_histo, histogram_symbols);
1199
1200
if (!WebPReportProgress(pic, *percent + percent_range, percent)) {
1201
goto Error;
1202
}
1203
1204
Error:
1205
VP8LFreeHistogramSet(orig_histo);
1206
return (pic->error_code == VP8_ENC_OK);
1207
}
1208
1209