/* Temporary data for ZopfliCostModelSetFromCommands. */ typedefstruct ZopfliCostModelArena {
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE]; float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
} ZopfliCostModelArena;
/* Histogram based cost model for zopflification. */ typedefstruct ZopfliCostModel { /* The insert and copy length symbols. */ float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS]; float* cost_dist_;
uint32_t distance_histogram_size; /* Cumulative costs of literals per position in the stream. */ float* literal_costs_; float min_cost_cmd_;
size_t num_bytes_;
/* Returns the minimum possible copy length that can improve the cost of any */ /* future position. */ static size_t ComputeMinimumCopyLength(constfloat start_cost, const ZopfliNode* nodes, const size_t num_bytes, const size_t pos) { /* Compute the minimum possible cost of reaching any future position. */ float min_cost = start_cost;
size_t len = 2;
size_t next_len_bucket = 4;
size_t next_len_offset = 10; while (pos + len <= num_bytes && nodes[pos + len].u.cost <= min_cost) { /* We already reached (pos + len) with no more cost than the minimum possiblecostofreachinganythingfromthispos,sothereisnopointin
looking for lengths <= len. */
++len; if (len == next_len_offset) { /* We reached the next copy length code bucket, so we add one more
extra bit to the minimum cost. */
min_cost += 1.0f;
next_len_offset += next_len_bucket;
next_len_bucket *= 2;
}
} return len;
}
/* REQUIRES: nodes[pos].cost < kInfinity
REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */ static uint32_t ComputeDistanceShortcut(const size_t block_start, const size_t pos, const size_t max_backward_limit, const size_t gap, const ZopfliNode* nodes) { const size_t c_len = ZopfliNodeCopyLength(&nodes[pos]); const size_t i_len = nodes[pos].dcode_insert_length & 0x7FFFFFF; const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]); /* Since |block_start + pos| is the end position of the command, the copy part startsfrom|block_start+pos-c_len|.Distancesthataregreaterthan thisorgreaterthan|max_backward_limit|+|gap|arestaticdictionary references,anddonotupdatethelastdistances.
Also distance code 0 (last distance) does not update the last distances. */ if (pos == 0) { return0;
} elseif (dist + c_len <= block_start + pos + gap &&
dist <= max_backward_limit + gap &&
ZopfliNodeDistanceCode(&nodes[pos]) > 0) { return (uint32_t)pos;
} else { return nodes[pos - c_len - i_len].u.shortcut;
}
}
/* Fills in dist_cache[0..3] with the last four distances (as defined by Section4.oftheSpec)thatwouldbeusedat(block_start+pos)ifwe usedtheshortestpathofcommandsfromblock_start,computedfrom nodes[0..pos].Thelastfourdistancesatblock_startarein starting_dist_cache[0..3]. REQUIRES:nodes[pos].cost<kInfinity
REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */ staticvoid ComputeDistanceCache(const size_t pos, constint* starting_dist_cache, const ZopfliNode* nodes, int* dist_cache) { int idx = 0;
size_t p = nodes[pos].u.shortcut; while (idx < 4 && p > 0) { const size_t i_len = nodes[p].dcode_insert_length & 0x7FFFFFF; const size_t c_len = ZopfliNodeCopyLength(&nodes[p]); const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
dist_cache[idx++] = (int)dist; /* Because of prerequisite, p >= c_len + i_len >= 2. */
p = nodes[p - c_len - i_len].u.shortcut;
} for (; idx < 4; ++idx) {
dist_cache[idx] = *starting_dist_cache++;
}
}
/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
is eligible. */ staticvoid EvaluateNode( const size_t block_start, const size_t pos, const size_t max_backward_limit, const size_t gap, constint* starting_dist_cache, const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) { /* Save cost, because ComputeDistanceCache invalidates it. */ float node_cost = nodes[pos].u.cost;
nodes[pos].u.shortcut = ComputeDistanceShortcut(
block_start, pos, max_backward_limit, gap, nodes); if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) {
PosData posdata;
posdata.pos = pos;
posdata.cost = node_cost;
posdata.costdiff = node_cost -
ZopfliCostModelGetLiteralCosts(model, 0, pos);
ComputeDistanceCache(
pos, starting_dist_cache, nodes, posdata.distance_cache);
StartPosQueuePush(queue, &posdata);
}
}
/* Go over the command starting positions in order of increasing cost
difference. */ for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k) { const PosData* posdata = StartPosQueueAt(queue, k); const size_t start = posdata->pos; const uint16_t inscode = GetInsertLengthCode(pos - start); constfloat start_costdiff = posdata->costdiff; constfloat base_cost = start_costdiff + (float)GetInsertExtra(inscode) +
ZopfliCostModelGetLiteralCosts(model, 0, pos);
/* Look for last distance matches using the distance cache from this
starting position. */
size_t best_len = min_len - 1;
size_t j = 0; for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j) { const size_t idx = kDistanceCacheIndex[j]; const size_t backward =
(size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]);
size_t prev_ix = cur_ix - backward;
size_t len = 0;
uint8_t continuation = ringbuffer[cur_ix_masked + best_len]; if (cur_ix_masked + best_len > ringbuffer_mask) { break;
} if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) { /* Word dictionary -> ignore. */ continue;
} if (backward <= max_distance) { /* Regular backward reference. */ if (prev_ix >= cur_ix) { continue;
}
prev_ix &= ringbuffer_mask; if (prev_ix + best_len > ringbuffer_mask ||
continuation != ringbuffer[prev_ix + best_len]) { continue;
}
len = FindMatchLengthWithLimit(&ringbuffer[prev_ix],
&ringbuffer[cur_ix_masked],
max_len);
} elseif (backward > dictionary_start) {
size_t d = 0;
size_t offset;
size_t limit; const uint8_t* source;
offset = dictionary_start + 1 + addon->total_size - 1; while (offset >= backward + addon->chunk_offsets[d + 1]) d++;
source = addon->chunk_source[d];
offset = offset - addon->chunk_offsets[d] - backward;
limit = addon->chunk_offsets[d + 1] - addon->chunk_offsets[d] - offset;
limit = limit > max_len ? max_len : limit; if (best_len >= limit ||
continuation != source[offset + best_len]) { continue;
}
len = FindMatchLengthWithLimit(&source[offset],
&ringbuffer[cur_ix_masked],
limit);
} else { /* "Gray" area. It is addressable by decoder, but this encoder
instance does not have that data -> should not touch it. */ continue;
}
{ constfloat dist_cost = base_cost +
ZopfliCostModelGetDistanceCost(model, j);
size_t l; for (l = best_len + 1; l <= len; ++l) { const uint16_t copycode = GetCopyLengthCode(l); const uint16_t cmdcode =
CombineLengthCodes(inscode, copycode, j == 0); constfloat cost = (cmdcode < 128 ? base_cost : dist_cost) +
(float)GetCopyExtra(copycode) +
ZopfliCostModelGetCommandCost(model, cmdcode); if (cost < nodes[pos + l].u.cost) {
UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost);
result = BROTLI_MAX(size_t, result, l);
}
best_len = l;
}
}
}
/* At higher iterations look only for new last distance matches, since lookingonlyfornewcommandstartpositionswiththesamedistances
does not help much. */ if (k >= 2) continue;
{ /* Loop through all possible copy lengths at this position. */
size_t len = min_len; for (j = 0; j < num_matches; ++j) {
BackwardMatch match = matches[j];
size_t dist = match.distance;
BROTLI_BOOL is_dictionary_match =
TO_BROTLI_BOOL(dist > dictionary_start + gap); /* We already tried all possible last distance matches, so we can use
normal distance code here. */
size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
uint16_t dist_symbol;
uint32_t distextra;
uint32_t distnumextra; float dist_cost;
size_t max_match_len;
PrefixEncodeCopyDistance(
dist_code, params->dist.num_direct_distance_codes,
params->dist.distance_postfix_bits, &dist_symbol, &distextra);
distnumextra = dist_symbol >> 10;
dist_cost = base_cost + (float)distnumextra +
ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF);
/* Try all copy lengths up until the maximum copy length corresponding tothisdistance.Ifthedistancereferstothestaticdictionary,or
the maximum length is long enough, try only one maximum length. */
max_match_len = BackwardMatchLength(&match); if (len < max_match_len &&
(is_dictionary_match || max_match_len > max_zopfli_len)) {
len = max_match_len;
} for (; len <= max_match_len; ++len) { const size_t len_code =
is_dictionary_match ? BackwardMatchLengthCode(&match) : len; const uint16_t copycode = GetCopyLengthCode(len_code); const uint16_t cmdcode = CombineLengthCodes(inscode, copycode, 0); constfloat cost = dist_cost + (float)GetCopyExtra(copycode) +
ZopfliCostModelGetCommandCost(model, cmdcode); if (cost < nodes[pos + len].u.cost) {
UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost);
result = BROTLI_MAX(size_t, result, len);
}
}
}
}
} return result;
}
static size_t ComputeShortestPathFromNodes(size_t num_bytes,
ZopfliNode* nodes) {
size_t index = num_bytes;
size_t num_commands = 0; while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 &&
nodes[index].length == 1) --index;
nodes[index].u.next = BROTLI_UINT32_MAX; while (index != 0) {
size_t len = ZopfliNodeCommandLength(&nodes[index]);
index -= len;
nodes[index].u.next = (uint32_t)len;
num_commands++;
} return num_commands;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.