1*6777b538SAndroid Build Coastguard Worker /* Copyright 2015 Google Inc. All Rights Reserved.
2*6777b538SAndroid Build Coastguard Worker
3*6777b538SAndroid Build Coastguard Worker Distributed under MIT license.
4*6777b538SAndroid Build Coastguard Worker See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5*6777b538SAndroid Build Coastguard Worker */
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker /* Algorithms for distributing the literals and commands of a metablock between
8*6777b538SAndroid Build Coastguard Worker block types and contexts. */
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "metablock.h"
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include "../common/constants.h"
13*6777b538SAndroid Build Coastguard Worker #include "../common/context.h"
14*6777b538SAndroid Build Coastguard Worker #include "../common/platform.h"
15*6777b538SAndroid Build Coastguard Worker #include <brotli/types.h>
16*6777b538SAndroid Build Coastguard Worker #include "bit_cost.h"
17*6777b538SAndroid Build Coastguard Worker #include "block_splitter.h"
18*6777b538SAndroid Build Coastguard Worker #include "cluster.h"
19*6777b538SAndroid Build Coastguard Worker #include "entropy_encode.h"
20*6777b538SAndroid Build Coastguard Worker #include "histogram.h"
21*6777b538SAndroid Build Coastguard Worker #include "memory.h"
22*6777b538SAndroid Build Coastguard Worker #include "quality.h"
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker #if defined(__cplusplus) || defined(c_plusplus)
25*6777b538SAndroid Build Coastguard Worker extern "C" {
26*6777b538SAndroid Build Coastguard Worker #endif
27*6777b538SAndroid Build Coastguard Worker
BrotliInitDistanceParams(BrotliDistanceParams * dist_params,uint32_t npostfix,uint32_t ndirect,BROTLI_BOOL large_window)28*6777b538SAndroid Build Coastguard Worker void BrotliInitDistanceParams(BrotliDistanceParams* dist_params,
29*6777b538SAndroid Build Coastguard Worker uint32_t npostfix, uint32_t ndirect, BROTLI_BOOL large_window) {
30*6777b538SAndroid Build Coastguard Worker uint32_t alphabet_size_max;
31*6777b538SAndroid Build Coastguard Worker uint32_t alphabet_size_limit;
32*6777b538SAndroid Build Coastguard Worker uint32_t max_distance;
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker dist_params->distance_postfix_bits = npostfix;
35*6777b538SAndroid Build Coastguard Worker dist_params->num_direct_distance_codes = ndirect;
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
38*6777b538SAndroid Build Coastguard Worker npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
39*6777b538SAndroid Build Coastguard Worker alphabet_size_limit = alphabet_size_max;
40*6777b538SAndroid Build Coastguard Worker max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
41*6777b538SAndroid Build Coastguard Worker (1U << (npostfix + 2));
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker if (large_window) {
44*6777b538SAndroid Build Coastguard Worker BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
45*6777b538SAndroid Build Coastguard Worker BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
46*6777b538SAndroid Build Coastguard Worker alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
47*6777b538SAndroid Build Coastguard Worker npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
48*6777b538SAndroid Build Coastguard Worker alphabet_size_limit = limit.max_alphabet_size;
49*6777b538SAndroid Build Coastguard Worker max_distance = limit.max_distance;
50*6777b538SAndroid Build Coastguard Worker }
51*6777b538SAndroid Build Coastguard Worker
52*6777b538SAndroid Build Coastguard Worker dist_params->alphabet_size_max = alphabet_size_max;
53*6777b538SAndroid Build Coastguard Worker dist_params->alphabet_size_limit = alphabet_size_limit;
54*6777b538SAndroid Build Coastguard Worker dist_params->max_distance = max_distance;
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker
RecomputeDistancePrefixes(Command * cmds,size_t num_commands,const BrotliDistanceParams * orig_params,const BrotliDistanceParams * new_params)57*6777b538SAndroid Build Coastguard Worker static void RecomputeDistancePrefixes(Command* cmds,
58*6777b538SAndroid Build Coastguard Worker size_t num_commands,
59*6777b538SAndroid Build Coastguard Worker const BrotliDistanceParams* orig_params,
60*6777b538SAndroid Build Coastguard Worker const BrotliDistanceParams* new_params) {
61*6777b538SAndroid Build Coastguard Worker size_t i;
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
64*6777b538SAndroid Build Coastguard Worker orig_params->num_direct_distance_codes ==
65*6777b538SAndroid Build Coastguard Worker new_params->num_direct_distance_codes) {
66*6777b538SAndroid Build Coastguard Worker return;
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker for (i = 0; i < num_commands; ++i) {
70*6777b538SAndroid Build Coastguard Worker Command* cmd = &cmds[i];
71*6777b538SAndroid Build Coastguard Worker if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
72*6777b538SAndroid Build Coastguard Worker PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params),
73*6777b538SAndroid Build Coastguard Worker new_params->num_direct_distance_codes,
74*6777b538SAndroid Build Coastguard Worker new_params->distance_postfix_bits,
75*6777b538SAndroid Build Coastguard Worker &cmd->dist_prefix_,
76*6777b538SAndroid Build Coastguard Worker &cmd->dist_extra_);
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker }
79*6777b538SAndroid Build Coastguard Worker }
80*6777b538SAndroid Build Coastguard Worker
ComputeDistanceCost(const Command * cmds,size_t num_commands,const BrotliDistanceParams * orig_params,const BrotliDistanceParams * new_params,double * cost,HistogramDistance * tmp)81*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
82*6777b538SAndroid Build Coastguard Worker size_t num_commands,
83*6777b538SAndroid Build Coastguard Worker const BrotliDistanceParams* orig_params,
84*6777b538SAndroid Build Coastguard Worker const BrotliDistanceParams* new_params,
85*6777b538SAndroid Build Coastguard Worker double* cost,
86*6777b538SAndroid Build Coastguard Worker HistogramDistance* tmp) {
87*6777b538SAndroid Build Coastguard Worker size_t i;
88*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL equal_params = BROTLI_FALSE;
89*6777b538SAndroid Build Coastguard Worker uint16_t dist_prefix;
90*6777b538SAndroid Build Coastguard Worker uint32_t dist_extra;
91*6777b538SAndroid Build Coastguard Worker double extra_bits = 0.0;
92*6777b538SAndroid Build Coastguard Worker HistogramClearDistance(tmp);
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
95*6777b538SAndroid Build Coastguard Worker orig_params->num_direct_distance_codes ==
96*6777b538SAndroid Build Coastguard Worker new_params->num_direct_distance_codes) {
97*6777b538SAndroid Build Coastguard Worker equal_params = BROTLI_TRUE;
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard Worker for (i = 0; i < num_commands; i++) {
101*6777b538SAndroid Build Coastguard Worker const Command* cmd = &cmds[i];
102*6777b538SAndroid Build Coastguard Worker if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
103*6777b538SAndroid Build Coastguard Worker if (equal_params) {
104*6777b538SAndroid Build Coastguard Worker dist_prefix = cmd->dist_prefix_;
105*6777b538SAndroid Build Coastguard Worker } else {
106*6777b538SAndroid Build Coastguard Worker uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params);
107*6777b538SAndroid Build Coastguard Worker if (distance > new_params->max_distance) {
108*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
109*6777b538SAndroid Build Coastguard Worker }
110*6777b538SAndroid Build Coastguard Worker PrefixEncodeCopyDistance(distance,
111*6777b538SAndroid Build Coastguard Worker new_params->num_direct_distance_codes,
112*6777b538SAndroid Build Coastguard Worker new_params->distance_postfix_bits,
113*6777b538SAndroid Build Coastguard Worker &dist_prefix,
114*6777b538SAndroid Build Coastguard Worker &dist_extra);
115*6777b538SAndroid Build Coastguard Worker }
116*6777b538SAndroid Build Coastguard Worker HistogramAddDistance(tmp, dist_prefix & 0x3FF);
117*6777b538SAndroid Build Coastguard Worker extra_bits += dist_prefix >> 10;
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker *cost = BrotliPopulationCostDistance(tmp) + extra_bits;
122*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker
BrotliBuildMetaBlock(MemoryManager * m,const uint8_t * ringbuffer,const size_t pos,const size_t mask,BrotliEncoderParams * params,uint8_t prev_byte,uint8_t prev_byte2,Command * cmds,size_t num_commands,ContextType literal_context_mode,MetaBlockSplit * mb)125*6777b538SAndroid Build Coastguard Worker void BrotliBuildMetaBlock(MemoryManager* m,
126*6777b538SAndroid Build Coastguard Worker const uint8_t* ringbuffer,
127*6777b538SAndroid Build Coastguard Worker const size_t pos,
128*6777b538SAndroid Build Coastguard Worker const size_t mask,
129*6777b538SAndroid Build Coastguard Worker BrotliEncoderParams* params,
130*6777b538SAndroid Build Coastguard Worker uint8_t prev_byte,
131*6777b538SAndroid Build Coastguard Worker uint8_t prev_byte2,
132*6777b538SAndroid Build Coastguard Worker Command* cmds,
133*6777b538SAndroid Build Coastguard Worker size_t num_commands,
134*6777b538SAndroid Build Coastguard Worker ContextType literal_context_mode,
135*6777b538SAndroid Build Coastguard Worker MetaBlockSplit* mb) {
136*6777b538SAndroid Build Coastguard Worker /* Histogram ids need to fit in one byte. */
137*6777b538SAndroid Build Coastguard Worker static const size_t kMaxNumberOfHistograms = 256;
138*6777b538SAndroid Build Coastguard Worker HistogramDistance* distance_histograms;
139*6777b538SAndroid Build Coastguard Worker HistogramLiteral* literal_histograms;
140*6777b538SAndroid Build Coastguard Worker ContextType* literal_context_modes = NULL;
141*6777b538SAndroid Build Coastguard Worker size_t literal_histograms_size;
142*6777b538SAndroid Build Coastguard Worker size_t distance_histograms_size;
143*6777b538SAndroid Build Coastguard Worker size_t i;
144*6777b538SAndroid Build Coastguard Worker size_t literal_context_multiplier = 1;
145*6777b538SAndroid Build Coastguard Worker uint32_t npostfix;
146*6777b538SAndroid Build Coastguard Worker uint32_t ndirect_msb = 0;
147*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL check_orig = BROTLI_TRUE;
148*6777b538SAndroid Build Coastguard Worker double best_dist_cost = 1e99;
149*6777b538SAndroid Build Coastguard Worker BrotliDistanceParams orig_params = params->dist;
150*6777b538SAndroid Build Coastguard Worker BrotliDistanceParams new_params = params->dist;
151*6777b538SAndroid Build Coastguard Worker HistogramDistance* tmp = BROTLI_ALLOC(m, HistogramDistance, 1);
152*6777b538SAndroid Build Coastguard Worker
153*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return;
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) {
156*6777b538SAndroid Build Coastguard Worker for (; ndirect_msb < 16; ndirect_msb++) {
157*6777b538SAndroid Build Coastguard Worker uint32_t ndirect = ndirect_msb << npostfix;
158*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL skip;
159*6777b538SAndroid Build Coastguard Worker double dist_cost;
160*6777b538SAndroid Build Coastguard Worker BrotliInitDistanceParams(&new_params, npostfix, ndirect,
161*6777b538SAndroid Build Coastguard Worker params->large_window);
162*6777b538SAndroid Build Coastguard Worker if (npostfix == orig_params.distance_postfix_bits &&
163*6777b538SAndroid Build Coastguard Worker ndirect == orig_params.num_direct_distance_codes) {
164*6777b538SAndroid Build Coastguard Worker check_orig = BROTLI_FALSE;
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker skip = !ComputeDistanceCost(
167*6777b538SAndroid Build Coastguard Worker cmds, num_commands, &orig_params, &new_params, &dist_cost, tmp);
168*6777b538SAndroid Build Coastguard Worker if (skip || (dist_cost > best_dist_cost)) {
169*6777b538SAndroid Build Coastguard Worker break;
170*6777b538SAndroid Build Coastguard Worker }
171*6777b538SAndroid Build Coastguard Worker best_dist_cost = dist_cost;
172*6777b538SAndroid Build Coastguard Worker params->dist = new_params;
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker if (ndirect_msb > 0) ndirect_msb--;
175*6777b538SAndroid Build Coastguard Worker ndirect_msb /= 2;
176*6777b538SAndroid Build Coastguard Worker }
177*6777b538SAndroid Build Coastguard Worker if (check_orig) {
178*6777b538SAndroid Build Coastguard Worker double dist_cost;
179*6777b538SAndroid Build Coastguard Worker ComputeDistanceCost(cmds, num_commands, &orig_params, &orig_params,
180*6777b538SAndroid Build Coastguard Worker &dist_cost, tmp);
181*6777b538SAndroid Build Coastguard Worker if (dist_cost < best_dist_cost) {
182*6777b538SAndroid Build Coastguard Worker /* NB: currently unused; uncomment when more param tuning is added. */
183*6777b538SAndroid Build Coastguard Worker /* best_dist_cost = dist_cost; */
184*6777b538SAndroid Build Coastguard Worker params->dist = orig_params;
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker }
187*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, tmp);
188*6777b538SAndroid Build Coastguard Worker RecomputeDistancePrefixes(cmds, num_commands, &orig_params, ¶ms->dist);
189*6777b538SAndroid Build Coastguard Worker
190*6777b538SAndroid Build Coastguard Worker BrotliSplitBlock(m, cmds, num_commands,
191*6777b538SAndroid Build Coastguard Worker ringbuffer, pos, mask, params,
192*6777b538SAndroid Build Coastguard Worker &mb->literal_split,
193*6777b538SAndroid Build Coastguard Worker &mb->command_split,
194*6777b538SAndroid Build Coastguard Worker &mb->distance_split);
195*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
196*6777b538SAndroid Build Coastguard Worker
197*6777b538SAndroid Build Coastguard Worker if (!params->disable_literal_context_modeling) {
198*6777b538SAndroid Build Coastguard Worker literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
199*6777b538SAndroid Build Coastguard Worker literal_context_modes =
200*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
201*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return;
202*6777b538SAndroid Build Coastguard Worker for (i = 0; i < mb->literal_split.num_types; ++i) {
203*6777b538SAndroid Build Coastguard Worker literal_context_modes[i] = literal_context_mode;
204*6777b538SAndroid Build Coastguard Worker }
205*6777b538SAndroid Build Coastguard Worker }
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker literal_histograms_size =
208*6777b538SAndroid Build Coastguard Worker mb->literal_split.num_types * literal_context_multiplier;
209*6777b538SAndroid Build Coastguard Worker literal_histograms =
210*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
211*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return;
212*6777b538SAndroid Build Coastguard Worker ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
213*6777b538SAndroid Build Coastguard Worker
214*6777b538SAndroid Build Coastguard Worker distance_histograms_size =
215*6777b538SAndroid Build Coastguard Worker mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
216*6777b538SAndroid Build Coastguard Worker distance_histograms =
217*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
218*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return;
219*6777b538SAndroid Build Coastguard Worker ClearHistogramsDistance(distance_histograms, distance_histograms_size);
220*6777b538SAndroid Build Coastguard Worker
221*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(mb->command_histograms == 0);
222*6777b538SAndroid Build Coastguard Worker mb->command_histograms_size = mb->command_split.num_types;
223*6777b538SAndroid Build Coastguard Worker mb->command_histograms =
224*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
225*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return;
226*6777b538SAndroid Build Coastguard Worker ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
227*6777b538SAndroid Build Coastguard Worker
228*6777b538SAndroid Build Coastguard Worker BrotliBuildHistogramsWithContext(cmds, num_commands,
229*6777b538SAndroid Build Coastguard Worker &mb->literal_split, &mb->command_split, &mb->distance_split,
230*6777b538SAndroid Build Coastguard Worker ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes,
231*6777b538SAndroid Build Coastguard Worker literal_histograms, mb->command_histograms, distance_histograms);
232*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, literal_context_modes);
233*6777b538SAndroid Build Coastguard Worker
234*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(mb->literal_context_map == 0);
235*6777b538SAndroid Build Coastguard Worker mb->literal_context_map_size =
236*6777b538SAndroid Build Coastguard Worker mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
237*6777b538SAndroid Build Coastguard Worker mb->literal_context_map =
238*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
239*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
240*6777b538SAndroid Build Coastguard Worker
241*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(mb->literal_histograms == 0);
242*6777b538SAndroid Build Coastguard Worker mb->literal_histograms_size = mb->literal_context_map_size;
243*6777b538SAndroid Build Coastguard Worker mb->literal_histograms =
244*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
245*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return;
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
248*6777b538SAndroid Build Coastguard Worker kMaxNumberOfHistograms, mb->literal_histograms,
249*6777b538SAndroid Build Coastguard Worker &mb->literal_histograms_size, mb->literal_context_map);
250*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
251*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, literal_histograms);
252*6777b538SAndroid Build Coastguard Worker
253*6777b538SAndroid Build Coastguard Worker if (params->disable_literal_context_modeling) {
254*6777b538SAndroid Build Coastguard Worker /* Distribute assignment to all contexts. */
255*6777b538SAndroid Build Coastguard Worker for (i = mb->literal_split.num_types; i != 0;) {
256*6777b538SAndroid Build Coastguard Worker size_t j = 0;
257*6777b538SAndroid Build Coastguard Worker i--;
258*6777b538SAndroid Build Coastguard Worker for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) {
259*6777b538SAndroid Build Coastguard Worker mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
260*6777b538SAndroid Build Coastguard Worker mb->literal_context_map[i];
261*6777b538SAndroid Build Coastguard Worker }
262*6777b538SAndroid Build Coastguard Worker }
263*6777b538SAndroid Build Coastguard Worker }
264*6777b538SAndroid Build Coastguard Worker
265*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(mb->distance_context_map == 0);
266*6777b538SAndroid Build Coastguard Worker mb->distance_context_map_size =
267*6777b538SAndroid Build Coastguard Worker mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
268*6777b538SAndroid Build Coastguard Worker mb->distance_context_map =
269*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
270*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return;
271*6777b538SAndroid Build Coastguard Worker
272*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(mb->distance_histograms == 0);
273*6777b538SAndroid Build Coastguard Worker mb->distance_histograms_size = mb->distance_context_map_size;
274*6777b538SAndroid Build Coastguard Worker mb->distance_histograms =
275*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
276*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return;
277*6777b538SAndroid Build Coastguard Worker
278*6777b538SAndroid Build Coastguard Worker BrotliClusterHistogramsDistance(m, distance_histograms,
279*6777b538SAndroid Build Coastguard Worker mb->distance_context_map_size,
280*6777b538SAndroid Build Coastguard Worker kMaxNumberOfHistograms,
281*6777b538SAndroid Build Coastguard Worker mb->distance_histograms,
282*6777b538SAndroid Build Coastguard Worker &mb->distance_histograms_size,
283*6777b538SAndroid Build Coastguard Worker mb->distance_context_map);
284*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
285*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, distance_histograms);
286*6777b538SAndroid Build Coastguard Worker }
287*6777b538SAndroid Build Coastguard Worker
288*6777b538SAndroid Build Coastguard Worker #define FN(X) X ## Literal
289*6777b538SAndroid Build Coastguard Worker #include "metablock_inc.h" /* NOLINT(build/include) */
290*6777b538SAndroid Build Coastguard Worker #undef FN
291*6777b538SAndroid Build Coastguard Worker
292*6777b538SAndroid Build Coastguard Worker #define FN(X) X ## Command
293*6777b538SAndroid Build Coastguard Worker #include "metablock_inc.h" /* NOLINT(build/include) */
294*6777b538SAndroid Build Coastguard Worker #undef FN
295*6777b538SAndroid Build Coastguard Worker
296*6777b538SAndroid Build Coastguard Worker #define FN(X) X ## Distance
297*6777b538SAndroid Build Coastguard Worker #include "metablock_inc.h" /* NOLINT(build/include) */
298*6777b538SAndroid Build Coastguard Worker #undef FN
299*6777b538SAndroid Build Coastguard Worker
300*6777b538SAndroid Build Coastguard Worker #define BROTLI_MAX_STATIC_CONTEXTS 13
301*6777b538SAndroid Build Coastguard Worker
302*6777b538SAndroid Build Coastguard Worker /* Greedy block splitter for one block category (literal, command or distance).
303*6777b538SAndroid Build Coastguard Worker Gathers histograms for all context buckets. */
304*6777b538SAndroid Build Coastguard Worker typedef struct ContextBlockSplitter {
305*6777b538SAndroid Build Coastguard Worker /* Alphabet size of particular block category. */
306*6777b538SAndroid Build Coastguard Worker size_t alphabet_size_;
307*6777b538SAndroid Build Coastguard Worker size_t num_contexts_;
308*6777b538SAndroid Build Coastguard Worker size_t max_block_types_;
309*6777b538SAndroid Build Coastguard Worker /* We collect at least this many symbols for each block. */
310*6777b538SAndroid Build Coastguard Worker size_t min_block_size_;
311*6777b538SAndroid Build Coastguard Worker /* We merge histograms A and B if
312*6777b538SAndroid Build Coastguard Worker entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
313*6777b538SAndroid Build Coastguard Worker where A is the current histogram and B is the histogram of the last or the
314*6777b538SAndroid Build Coastguard Worker second last block type. */
315*6777b538SAndroid Build Coastguard Worker double split_threshold_;
316*6777b538SAndroid Build Coastguard Worker
317*6777b538SAndroid Build Coastguard Worker size_t num_blocks_;
318*6777b538SAndroid Build Coastguard Worker BlockSplit* split_; /* not owned */
319*6777b538SAndroid Build Coastguard Worker HistogramLiteral* histograms_; /* not owned */
320*6777b538SAndroid Build Coastguard Worker size_t* histograms_size_; /* not owned */
321*6777b538SAndroid Build Coastguard Worker
322*6777b538SAndroid Build Coastguard Worker /* The number of symbols that we want to collect before deciding on whether
323*6777b538SAndroid Build Coastguard Worker or not to merge the block with a previous one or emit a new block. */
324*6777b538SAndroid Build Coastguard Worker size_t target_block_size_;
325*6777b538SAndroid Build Coastguard Worker /* The number of symbols in the current histogram. */
326*6777b538SAndroid Build Coastguard Worker size_t block_size_;
327*6777b538SAndroid Build Coastguard Worker /* Offset of the current histogram. */
328*6777b538SAndroid Build Coastguard Worker size_t curr_histogram_ix_;
329*6777b538SAndroid Build Coastguard Worker /* Offset of the histograms of the previous two block types. */
330*6777b538SAndroid Build Coastguard Worker size_t last_histogram_ix_[2];
331*6777b538SAndroid Build Coastguard Worker /* Entropy of the previous two block types. */
332*6777b538SAndroid Build Coastguard Worker double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
333*6777b538SAndroid Build Coastguard Worker /* The number of times we merged the current block with the last one. */
334*6777b538SAndroid Build Coastguard Worker size_t merge_last_count_;
335*6777b538SAndroid Build Coastguard Worker } ContextBlockSplitter;
336*6777b538SAndroid Build Coastguard Worker
InitContextBlockSplitter(MemoryManager * m,ContextBlockSplitter * self,size_t alphabet_size,size_t num_contexts,size_t min_block_size,double split_threshold,size_t num_symbols,BlockSplit * split,HistogramLiteral ** histograms,size_t * histograms_size)337*6777b538SAndroid Build Coastguard Worker static void InitContextBlockSplitter(
338*6777b538SAndroid Build Coastguard Worker MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size,
339*6777b538SAndroid Build Coastguard Worker size_t num_contexts, size_t min_block_size, double split_threshold,
340*6777b538SAndroid Build Coastguard Worker size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms,
341*6777b538SAndroid Build Coastguard Worker size_t* histograms_size) {
342*6777b538SAndroid Build Coastguard Worker size_t max_num_blocks = num_symbols / min_block_size + 1;
343*6777b538SAndroid Build Coastguard Worker size_t max_num_types;
344*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
345*6777b538SAndroid Build Coastguard Worker
346*6777b538SAndroid Build Coastguard Worker self->alphabet_size_ = alphabet_size;
347*6777b538SAndroid Build Coastguard Worker self->num_contexts_ = num_contexts;
348*6777b538SAndroid Build Coastguard Worker self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts;
349*6777b538SAndroid Build Coastguard Worker self->min_block_size_ = min_block_size;
350*6777b538SAndroid Build Coastguard Worker self->split_threshold_ = split_threshold;
351*6777b538SAndroid Build Coastguard Worker self->num_blocks_ = 0;
352*6777b538SAndroid Build Coastguard Worker self->split_ = split;
353*6777b538SAndroid Build Coastguard Worker self->histograms_size_ = histograms_size;
354*6777b538SAndroid Build Coastguard Worker self->target_block_size_ = min_block_size;
355*6777b538SAndroid Build Coastguard Worker self->block_size_ = 0;
356*6777b538SAndroid Build Coastguard Worker self->curr_histogram_ix_ = 0;
357*6777b538SAndroid Build Coastguard Worker self->merge_last_count_ = 0;
358*6777b538SAndroid Build Coastguard Worker
359*6777b538SAndroid Build Coastguard Worker /* We have to allocate one more histogram than the maximum number of block
360*6777b538SAndroid Build Coastguard Worker types for the current histogram when the meta-block is too big. */
361*6777b538SAndroid Build Coastguard Worker max_num_types =
362*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1);
363*6777b538SAndroid Build Coastguard Worker BROTLI_ENSURE_CAPACITY(m, uint8_t,
364*6777b538SAndroid Build Coastguard Worker split->types, split->types_alloc_size, max_num_blocks);
365*6777b538SAndroid Build Coastguard Worker BROTLI_ENSURE_CAPACITY(m, uint32_t,
366*6777b538SAndroid Build Coastguard Worker split->lengths, split->lengths_alloc_size, max_num_blocks);
367*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
368*6777b538SAndroid Build Coastguard Worker split->num_blocks = max_num_blocks;
369*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
370*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(*histograms == 0);
371*6777b538SAndroid Build Coastguard Worker *histograms_size = max_num_types * num_contexts;
372*6777b538SAndroid Build Coastguard Worker *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
373*6777b538SAndroid Build Coastguard Worker self->histograms_ = *histograms;
374*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
375*6777b538SAndroid Build Coastguard Worker /* Clear only current histogram. */
376*6777b538SAndroid Build Coastguard Worker ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
377*6777b538SAndroid Build Coastguard Worker self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
378*6777b538SAndroid Build Coastguard Worker }
379*6777b538SAndroid Build Coastguard Worker
380*6777b538SAndroid Build Coastguard Worker /* Does either of three things:
381*6777b538SAndroid Build Coastguard Worker (1) emits the current block with a new block type;
382*6777b538SAndroid Build Coastguard Worker (2) emits the current block with the type of the second last block;
383*6777b538SAndroid Build Coastguard Worker (3) merges the current block with the last block. */
ContextBlockSplitterFinishBlock(ContextBlockSplitter * self,MemoryManager * m,BROTLI_BOOL is_final)384*6777b538SAndroid Build Coastguard Worker static void ContextBlockSplitterFinishBlock(
385*6777b538SAndroid Build Coastguard Worker ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
386*6777b538SAndroid Build Coastguard Worker BlockSplit* split = self->split_;
387*6777b538SAndroid Build Coastguard Worker const size_t num_contexts = self->num_contexts_;
388*6777b538SAndroid Build Coastguard Worker double* last_entropy = self->last_entropy_;
389*6777b538SAndroid Build Coastguard Worker HistogramLiteral* histograms = self->histograms_;
390*6777b538SAndroid Build Coastguard Worker
391*6777b538SAndroid Build Coastguard Worker if (self->block_size_ < self->min_block_size_) {
392*6777b538SAndroid Build Coastguard Worker self->block_size_ = self->min_block_size_;
393*6777b538SAndroid Build Coastguard Worker }
394*6777b538SAndroid Build Coastguard Worker if (self->num_blocks_ == 0) {
395*6777b538SAndroid Build Coastguard Worker size_t i;
396*6777b538SAndroid Build Coastguard Worker /* Create first block. */
397*6777b538SAndroid Build Coastguard Worker split->lengths[0] = (uint32_t)self->block_size_;
398*6777b538SAndroid Build Coastguard Worker split->types[0] = 0;
399*6777b538SAndroid Build Coastguard Worker
400*6777b538SAndroid Build Coastguard Worker for (i = 0; i < num_contexts; ++i) {
401*6777b538SAndroid Build Coastguard Worker last_entropy[i] =
402*6777b538SAndroid Build Coastguard Worker BitsEntropy(histograms[i].data_, self->alphabet_size_);
403*6777b538SAndroid Build Coastguard Worker last_entropy[num_contexts + i] = last_entropy[i];
404*6777b538SAndroid Build Coastguard Worker }
405*6777b538SAndroid Build Coastguard Worker ++self->num_blocks_;
406*6777b538SAndroid Build Coastguard Worker ++split->num_types;
407*6777b538SAndroid Build Coastguard Worker self->curr_histogram_ix_ += num_contexts;
408*6777b538SAndroid Build Coastguard Worker if (self->curr_histogram_ix_ < *self->histograms_size_) {
409*6777b538SAndroid Build Coastguard Worker ClearHistogramsLiteral(
410*6777b538SAndroid Build Coastguard Worker &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
411*6777b538SAndroid Build Coastguard Worker }
412*6777b538SAndroid Build Coastguard Worker self->block_size_ = 0;
413*6777b538SAndroid Build Coastguard Worker } else if (self->block_size_ > 0) {
414*6777b538SAndroid Build Coastguard Worker /* Try merging the set of histograms for the current block type with the
415*6777b538SAndroid Build Coastguard Worker respective set of histograms for the last and second last block types.
416*6777b538SAndroid Build Coastguard Worker Decide over the split based on the total reduction of entropy across
417*6777b538SAndroid Build Coastguard Worker all contexts. */
418*6777b538SAndroid Build Coastguard Worker double entropy[BROTLI_MAX_STATIC_CONTEXTS];
419*6777b538SAndroid Build Coastguard Worker HistogramLiteral* combined_histo =
420*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
421*6777b538SAndroid Build Coastguard Worker double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
422*6777b538SAndroid Build Coastguard Worker double diff[2] = { 0.0 };
423*6777b538SAndroid Build Coastguard Worker size_t i;
424*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
425*6777b538SAndroid Build Coastguard Worker for (i = 0; i < num_contexts; ++i) {
426*6777b538SAndroid Build Coastguard Worker size_t curr_histo_ix = self->curr_histogram_ix_ + i;
427*6777b538SAndroid Build Coastguard Worker size_t j;
428*6777b538SAndroid Build Coastguard Worker entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_,
429*6777b538SAndroid Build Coastguard Worker self->alphabet_size_);
430*6777b538SAndroid Build Coastguard Worker for (j = 0; j < 2; ++j) {
431*6777b538SAndroid Build Coastguard Worker size_t jx = j * num_contexts + i;
432*6777b538SAndroid Build Coastguard Worker size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
433*6777b538SAndroid Build Coastguard Worker combined_histo[jx] = histograms[curr_histo_ix];
434*6777b538SAndroid Build Coastguard Worker HistogramAddHistogramLiteral(&combined_histo[jx],
435*6777b538SAndroid Build Coastguard Worker &histograms[last_histogram_ix]);
436*6777b538SAndroid Build Coastguard Worker combined_entropy[jx] = BitsEntropy(
437*6777b538SAndroid Build Coastguard Worker &combined_histo[jx].data_[0], self->alphabet_size_);
438*6777b538SAndroid Build Coastguard Worker diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
439*6777b538SAndroid Build Coastguard Worker }
440*6777b538SAndroid Build Coastguard Worker }
441*6777b538SAndroid Build Coastguard Worker
442*6777b538SAndroid Build Coastguard Worker if (split->num_types < self->max_block_types_ &&
443*6777b538SAndroid Build Coastguard Worker diff[0] > self->split_threshold_ &&
444*6777b538SAndroid Build Coastguard Worker diff[1] > self->split_threshold_) {
445*6777b538SAndroid Build Coastguard Worker /* Create new block. */
446*6777b538SAndroid Build Coastguard Worker split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
447*6777b538SAndroid Build Coastguard Worker split->types[self->num_blocks_] = (uint8_t)split->num_types;
448*6777b538SAndroid Build Coastguard Worker self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
449*6777b538SAndroid Build Coastguard Worker self->last_histogram_ix_[0] = split->num_types * num_contexts;
450*6777b538SAndroid Build Coastguard Worker for (i = 0; i < num_contexts; ++i) {
451*6777b538SAndroid Build Coastguard Worker last_entropy[num_contexts + i] = last_entropy[i];
452*6777b538SAndroid Build Coastguard Worker last_entropy[i] = entropy[i];
453*6777b538SAndroid Build Coastguard Worker }
454*6777b538SAndroid Build Coastguard Worker ++self->num_blocks_;
455*6777b538SAndroid Build Coastguard Worker ++split->num_types;
456*6777b538SAndroid Build Coastguard Worker self->curr_histogram_ix_ += num_contexts;
457*6777b538SAndroid Build Coastguard Worker if (self->curr_histogram_ix_ < *self->histograms_size_) {
458*6777b538SAndroid Build Coastguard Worker ClearHistogramsLiteral(
459*6777b538SAndroid Build Coastguard Worker &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
460*6777b538SAndroid Build Coastguard Worker }
461*6777b538SAndroid Build Coastguard Worker self->block_size_ = 0;
462*6777b538SAndroid Build Coastguard Worker self->merge_last_count_ = 0;
463*6777b538SAndroid Build Coastguard Worker self->target_block_size_ = self->min_block_size_;
464*6777b538SAndroid Build Coastguard Worker } else if (diff[1] < diff[0] - 20.0) {
465*6777b538SAndroid Build Coastguard Worker /* Combine this block with second last block. */
466*6777b538SAndroid Build Coastguard Worker split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
467*6777b538SAndroid Build Coastguard Worker split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
468*6777b538SAndroid Build Coastguard Worker BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
469*6777b538SAndroid Build Coastguard Worker for (i = 0; i < num_contexts; ++i) {
470*6777b538SAndroid Build Coastguard Worker histograms[self->last_histogram_ix_[0] + i] =
471*6777b538SAndroid Build Coastguard Worker combined_histo[num_contexts + i];
472*6777b538SAndroid Build Coastguard Worker last_entropy[num_contexts + i] = last_entropy[i];
473*6777b538SAndroid Build Coastguard Worker last_entropy[i] = combined_entropy[num_contexts + i];
474*6777b538SAndroid Build Coastguard Worker HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
475*6777b538SAndroid Build Coastguard Worker }
476*6777b538SAndroid Build Coastguard Worker ++self->num_blocks_;
477*6777b538SAndroid Build Coastguard Worker self->block_size_ = 0;
478*6777b538SAndroid Build Coastguard Worker self->merge_last_count_ = 0;
479*6777b538SAndroid Build Coastguard Worker self->target_block_size_ = self->min_block_size_;
480*6777b538SAndroid Build Coastguard Worker } else {
481*6777b538SAndroid Build Coastguard Worker /* Combine this block with last block. */
482*6777b538SAndroid Build Coastguard Worker split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
483*6777b538SAndroid Build Coastguard Worker for (i = 0; i < num_contexts; ++i) {
484*6777b538SAndroid Build Coastguard Worker histograms[self->last_histogram_ix_[0] + i] = combined_histo[i];
485*6777b538SAndroid Build Coastguard Worker last_entropy[i] = combined_entropy[i];
486*6777b538SAndroid Build Coastguard Worker if (split->num_types == 1) {
487*6777b538SAndroid Build Coastguard Worker last_entropy[num_contexts + i] = last_entropy[i];
488*6777b538SAndroid Build Coastguard Worker }
489*6777b538SAndroid Build Coastguard Worker HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
490*6777b538SAndroid Build Coastguard Worker }
491*6777b538SAndroid Build Coastguard Worker self->block_size_ = 0;
492*6777b538SAndroid Build Coastguard Worker if (++self->merge_last_count_ > 1) {
493*6777b538SAndroid Build Coastguard Worker self->target_block_size_ += self->min_block_size_;
494*6777b538SAndroid Build Coastguard Worker }
495*6777b538SAndroid Build Coastguard Worker }
496*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, combined_histo);
497*6777b538SAndroid Build Coastguard Worker }
498*6777b538SAndroid Build Coastguard Worker if (is_final) {
499*6777b538SAndroid Build Coastguard Worker *self->histograms_size_ = split->num_types * num_contexts;
500*6777b538SAndroid Build Coastguard Worker split->num_blocks = self->num_blocks_;
501*6777b538SAndroid Build Coastguard Worker }
502*6777b538SAndroid Build Coastguard Worker }
503*6777b538SAndroid Build Coastguard Worker
504*6777b538SAndroid Build Coastguard Worker /* Adds the next symbol to the current block type and context. When the
505*6777b538SAndroid Build Coastguard Worker current block reaches the target size, decides on merging the block. */
ContextBlockSplitterAddSymbol(ContextBlockSplitter * self,MemoryManager * m,size_t symbol,size_t context)506*6777b538SAndroid Build Coastguard Worker static void ContextBlockSplitterAddSymbol(
507*6777b538SAndroid Build Coastguard Worker ContextBlockSplitter* self, MemoryManager* m,
508*6777b538SAndroid Build Coastguard Worker size_t symbol, size_t context) {
509*6777b538SAndroid Build Coastguard Worker HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
510*6777b538SAndroid Build Coastguard Worker symbol);
511*6777b538SAndroid Build Coastguard Worker ++self->block_size_;
512*6777b538SAndroid Build Coastguard Worker if (self->block_size_ == self->target_block_size_) {
513*6777b538SAndroid Build Coastguard Worker ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
514*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
515*6777b538SAndroid Build Coastguard Worker }
516*6777b538SAndroid Build Coastguard Worker }
517*6777b538SAndroid Build Coastguard Worker
MapStaticContexts(MemoryManager * m,size_t num_contexts,const uint32_t * static_context_map,MetaBlockSplit * mb)518*6777b538SAndroid Build Coastguard Worker static void MapStaticContexts(MemoryManager* m,
519*6777b538SAndroid Build Coastguard Worker size_t num_contexts,
520*6777b538SAndroid Build Coastguard Worker const uint32_t* static_context_map,
521*6777b538SAndroid Build Coastguard Worker MetaBlockSplit* mb) {
522*6777b538SAndroid Build Coastguard Worker size_t i;
523*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(mb->literal_context_map == 0);
524*6777b538SAndroid Build Coastguard Worker mb->literal_context_map_size =
525*6777b538SAndroid Build Coastguard Worker mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
526*6777b538SAndroid Build Coastguard Worker mb->literal_context_map =
527*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
528*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
529*6777b538SAndroid Build Coastguard Worker
530*6777b538SAndroid Build Coastguard Worker for (i = 0; i < mb->literal_split.num_types; ++i) {
531*6777b538SAndroid Build Coastguard Worker uint32_t offset = (uint32_t)(i * num_contexts);
532*6777b538SAndroid Build Coastguard Worker size_t j;
533*6777b538SAndroid Build Coastguard Worker for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
534*6777b538SAndroid Build Coastguard Worker mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
535*6777b538SAndroid Build Coastguard Worker offset + static_context_map[j];
536*6777b538SAndroid Build Coastguard Worker }
537*6777b538SAndroid Build Coastguard Worker }
538*6777b538SAndroid Build Coastguard Worker }
539*6777b538SAndroid Build Coastguard Worker
540*6777b538SAndroid Build Coastguard Worker typedef struct GreedyMetablockArena {
541*6777b538SAndroid Build Coastguard Worker union {
542*6777b538SAndroid Build Coastguard Worker BlockSplitterLiteral plain;
543*6777b538SAndroid Build Coastguard Worker ContextBlockSplitter ctx;
544*6777b538SAndroid Build Coastguard Worker } lit_blocks;
545*6777b538SAndroid Build Coastguard Worker BlockSplitterCommand cmd_blocks;
546*6777b538SAndroid Build Coastguard Worker BlockSplitterDistance dist_blocks;
547*6777b538SAndroid Build Coastguard Worker } GreedyMetablockArena;
548*6777b538SAndroid Build Coastguard Worker
BrotliBuildMetaBlockGreedyInternal(MemoryManager * m,GreedyMetablockArena * arena,const uint8_t * ringbuffer,size_t pos,size_t mask,uint8_t prev_byte,uint8_t prev_byte2,ContextLut literal_context_lut,const size_t num_contexts,const uint32_t * static_context_map,const Command * commands,size_t n_commands,MetaBlockSplit * mb)549*6777b538SAndroid Build Coastguard Worker static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
550*6777b538SAndroid Build Coastguard Worker MemoryManager* m, GreedyMetablockArena* arena, const uint8_t* ringbuffer,
551*6777b538SAndroid Build Coastguard Worker size_t pos, size_t mask, uint8_t prev_byte, uint8_t prev_byte2,
552*6777b538SAndroid Build Coastguard Worker ContextLut literal_context_lut, const size_t num_contexts,
553*6777b538SAndroid Build Coastguard Worker const uint32_t* static_context_map, const Command* commands,
554*6777b538SAndroid Build Coastguard Worker size_t n_commands, MetaBlockSplit* mb) {
555*6777b538SAndroid Build Coastguard Worker size_t num_literals = 0;
556*6777b538SAndroid Build Coastguard Worker size_t i;
557*6777b538SAndroid Build Coastguard Worker for (i = 0; i < n_commands; ++i) {
558*6777b538SAndroid Build Coastguard Worker num_literals += commands[i].insert_len_;
559*6777b538SAndroid Build Coastguard Worker }
560*6777b538SAndroid Build Coastguard Worker
561*6777b538SAndroid Build Coastguard Worker if (num_contexts == 1) {
562*6777b538SAndroid Build Coastguard Worker InitBlockSplitterLiteral(m, &arena->lit_blocks.plain, 256, 512, 400.0,
563*6777b538SAndroid Build Coastguard Worker num_literals, &mb->literal_split, &mb->literal_histograms,
564*6777b538SAndroid Build Coastguard Worker &mb->literal_histograms_size);
565*6777b538SAndroid Build Coastguard Worker } else {
566*6777b538SAndroid Build Coastguard Worker InitContextBlockSplitter(m, &arena->lit_blocks.ctx, 256, num_contexts, 512,
567*6777b538SAndroid Build Coastguard Worker 400.0, num_literals, &mb->literal_split, &mb->literal_histograms,
568*6777b538SAndroid Build Coastguard Worker &mb->literal_histograms_size);
569*6777b538SAndroid Build Coastguard Worker }
570*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
571*6777b538SAndroid Build Coastguard Worker InitBlockSplitterCommand(m, &arena->cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS,
572*6777b538SAndroid Build Coastguard Worker 1024, 500.0, n_commands, &mb->command_split, &mb->command_histograms,
573*6777b538SAndroid Build Coastguard Worker &mb->command_histograms_size);
574*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
575*6777b538SAndroid Build Coastguard Worker InitBlockSplitterDistance(m, &arena->dist_blocks, 64, 512, 100.0, n_commands,
576*6777b538SAndroid Build Coastguard Worker &mb->distance_split, &mb->distance_histograms,
577*6777b538SAndroid Build Coastguard Worker &mb->distance_histograms_size);
578*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
579*6777b538SAndroid Build Coastguard Worker
580*6777b538SAndroid Build Coastguard Worker for (i = 0; i < n_commands; ++i) {
581*6777b538SAndroid Build Coastguard Worker const Command cmd = commands[i];
582*6777b538SAndroid Build Coastguard Worker size_t j;
583*6777b538SAndroid Build Coastguard Worker BlockSplitterAddSymbolCommand(&arena->cmd_blocks, cmd.cmd_prefix_);
584*6777b538SAndroid Build Coastguard Worker for (j = cmd.insert_len_; j != 0; --j) {
585*6777b538SAndroid Build Coastguard Worker uint8_t literal = ringbuffer[pos & mask];
586*6777b538SAndroid Build Coastguard Worker if (num_contexts == 1) {
587*6777b538SAndroid Build Coastguard Worker BlockSplitterAddSymbolLiteral(&arena->lit_blocks.plain, literal);
588*6777b538SAndroid Build Coastguard Worker } else {
589*6777b538SAndroid Build Coastguard Worker size_t context =
590*6777b538SAndroid Build Coastguard Worker BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
591*6777b538SAndroid Build Coastguard Worker ContextBlockSplitterAddSymbol(&arena->lit_blocks.ctx, m, literal,
592*6777b538SAndroid Build Coastguard Worker static_context_map[context]);
593*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
594*6777b538SAndroid Build Coastguard Worker }
595*6777b538SAndroid Build Coastguard Worker prev_byte2 = prev_byte;
596*6777b538SAndroid Build Coastguard Worker prev_byte = literal;
597*6777b538SAndroid Build Coastguard Worker ++pos;
598*6777b538SAndroid Build Coastguard Worker }
599*6777b538SAndroid Build Coastguard Worker pos += CommandCopyLen(&cmd);
600*6777b538SAndroid Build Coastguard Worker if (CommandCopyLen(&cmd)) {
601*6777b538SAndroid Build Coastguard Worker prev_byte2 = ringbuffer[(pos - 2) & mask];
602*6777b538SAndroid Build Coastguard Worker prev_byte = ringbuffer[(pos - 1) & mask];
603*6777b538SAndroid Build Coastguard Worker if (cmd.cmd_prefix_ >= 128) {
604*6777b538SAndroid Build Coastguard Worker BlockSplitterAddSymbolDistance(
605*6777b538SAndroid Build Coastguard Worker &arena->dist_blocks, cmd.dist_prefix_ & 0x3FF);
606*6777b538SAndroid Build Coastguard Worker }
607*6777b538SAndroid Build Coastguard Worker }
608*6777b538SAndroid Build Coastguard Worker }
609*6777b538SAndroid Build Coastguard Worker
610*6777b538SAndroid Build Coastguard Worker if (num_contexts == 1) {
611*6777b538SAndroid Build Coastguard Worker BlockSplitterFinishBlockLiteral(
612*6777b538SAndroid Build Coastguard Worker &arena->lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
613*6777b538SAndroid Build Coastguard Worker } else {
614*6777b538SAndroid Build Coastguard Worker ContextBlockSplitterFinishBlock(
615*6777b538SAndroid Build Coastguard Worker &arena->lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
616*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
617*6777b538SAndroid Build Coastguard Worker }
618*6777b538SAndroid Build Coastguard Worker BlockSplitterFinishBlockCommand(
619*6777b538SAndroid Build Coastguard Worker &arena->cmd_blocks, /* is_final = */ BROTLI_TRUE);
620*6777b538SAndroid Build Coastguard Worker BlockSplitterFinishBlockDistance(
621*6777b538SAndroid Build Coastguard Worker &arena->dist_blocks, /* is_final = */ BROTLI_TRUE);
622*6777b538SAndroid Build Coastguard Worker
623*6777b538SAndroid Build Coastguard Worker if (num_contexts > 1) {
624*6777b538SAndroid Build Coastguard Worker MapStaticContexts(m, num_contexts, static_context_map, mb);
625*6777b538SAndroid Build Coastguard Worker }
626*6777b538SAndroid Build Coastguard Worker }
627*6777b538SAndroid Build Coastguard Worker
BrotliBuildMetaBlockGreedy(MemoryManager * m,const uint8_t * ringbuffer,size_t pos,size_t mask,uint8_t prev_byte,uint8_t prev_byte2,ContextLut literal_context_lut,size_t num_contexts,const uint32_t * static_context_map,const Command * commands,size_t n_commands,MetaBlockSplit * mb)628*6777b538SAndroid Build Coastguard Worker void BrotliBuildMetaBlockGreedy(MemoryManager* m,
629*6777b538SAndroid Build Coastguard Worker const uint8_t* ringbuffer,
630*6777b538SAndroid Build Coastguard Worker size_t pos,
631*6777b538SAndroid Build Coastguard Worker size_t mask,
632*6777b538SAndroid Build Coastguard Worker uint8_t prev_byte,
633*6777b538SAndroid Build Coastguard Worker uint8_t prev_byte2,
634*6777b538SAndroid Build Coastguard Worker ContextLut literal_context_lut,
635*6777b538SAndroid Build Coastguard Worker size_t num_contexts,
636*6777b538SAndroid Build Coastguard Worker const uint32_t* static_context_map,
637*6777b538SAndroid Build Coastguard Worker const Command* commands,
638*6777b538SAndroid Build Coastguard Worker size_t n_commands,
639*6777b538SAndroid Build Coastguard Worker MetaBlockSplit* mb) {
640*6777b538SAndroid Build Coastguard Worker GreedyMetablockArena* arena = BROTLI_ALLOC(m, GreedyMetablockArena, 1);
641*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
642*6777b538SAndroid Build Coastguard Worker if (num_contexts == 1) {
643*6777b538SAndroid Build Coastguard Worker BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask,
644*6777b538SAndroid Build Coastguard Worker prev_byte, prev_byte2, literal_context_lut, 1, NULL, commands,
645*6777b538SAndroid Build Coastguard Worker n_commands, mb);
646*6777b538SAndroid Build Coastguard Worker } else {
647*6777b538SAndroid Build Coastguard Worker BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask,
648*6777b538SAndroid Build Coastguard Worker prev_byte, prev_byte2, literal_context_lut, num_contexts,
649*6777b538SAndroid Build Coastguard Worker static_context_map, commands, n_commands, mb);
650*6777b538SAndroid Build Coastguard Worker }
651*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, arena);
652*6777b538SAndroid Build Coastguard Worker }
653*6777b538SAndroid Build Coastguard Worker
BrotliOptimizeHistograms(uint32_t num_distance_codes,MetaBlockSplit * mb)654*6777b538SAndroid Build Coastguard Worker void BrotliOptimizeHistograms(uint32_t num_distance_codes,
655*6777b538SAndroid Build Coastguard Worker MetaBlockSplit* mb) {
656*6777b538SAndroid Build Coastguard Worker uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
657*6777b538SAndroid Build Coastguard Worker size_t i;
658*6777b538SAndroid Build Coastguard Worker for (i = 0; i < mb->literal_histograms_size; ++i) {
659*6777b538SAndroid Build Coastguard Worker BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
660*6777b538SAndroid Build Coastguard Worker good_for_rle);
661*6777b538SAndroid Build Coastguard Worker }
662*6777b538SAndroid Build Coastguard Worker for (i = 0; i < mb->command_histograms_size; ++i) {
663*6777b538SAndroid Build Coastguard Worker BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS,
664*6777b538SAndroid Build Coastguard Worker mb->command_histograms[i].data_,
665*6777b538SAndroid Build Coastguard Worker good_for_rle);
666*6777b538SAndroid Build Coastguard Worker }
667*6777b538SAndroid Build Coastguard Worker for (i = 0; i < mb->distance_histograms_size; ++i) {
668*6777b538SAndroid Build Coastguard Worker BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
669*6777b538SAndroid Build Coastguard Worker mb->distance_histograms[i].data_,
670*6777b538SAndroid Build Coastguard Worker good_for_rle);
671*6777b538SAndroid Build Coastguard Worker }
672*6777b538SAndroid Build Coastguard Worker }
673*6777b538SAndroid Build Coastguard Worker
674*6777b538SAndroid Build Coastguard Worker #if defined(__cplusplus) || defined(c_plusplus)
675*6777b538SAndroid Build Coastguard Worker } /* extern "C" */
676*6777b538SAndroid Build Coastguard Worker #endif
677