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