Remove a useless malloc for entropy image

histogram_symbols is converted to uint32_t and <<8 into
histogram_argb.
Using a uint32_t buffer from the start prevents copying and
converting the data.

Change-Id: I245003a6a0f048c31519afa25a600d4479e762e3
This commit is contained in:
Vincent Rabaud 2024-09-18 17:30:31 +02:00
parent bc49176355
commit a78c5356ba
3 changed files with 38 additions and 47 deletions

View File

@ -601,11 +601,11 @@ static void HistogramBuild(
} }
// Copies the histograms and computes its bit_cost. // Copies the histograms and computes its bit_cost.
static const uint16_t kInvalidHistogramSymbol = (uint16_t)(-1); static const uint32_t kInvalidHistogramSymbol = (uint32_t)(-1);
static void HistogramCopyAndAnalyze(VP8LHistogramSet* const orig_histo, static void HistogramCopyAndAnalyze(VP8LHistogramSet* const orig_histo,
VP8LHistogramSet* const image_histo, VP8LHistogramSet* const image_histo,
int* const num_used, int* const num_used,
uint16_t* const histogram_symbols) { uint32_t* const histogram_symbols) {
int i, cluster_id; int i, cluster_id;
int num_used_orig = *num_used; int num_used_orig = *num_used;
VP8LHistogram** const orig_histograms = orig_histo->histograms; VP8LHistogram** const orig_histograms = orig_histo->histograms;
@ -667,7 +667,7 @@ static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
// 'combine_cost_factor' has to be divided by 100. // 'combine_cost_factor' has to be divided by 100.
static void HistogramCombineEntropyBin( static void HistogramCombineEntropyBin(
VP8LHistogramSet* const image_histo, int* num_used, VP8LHistogramSet* const image_histo, int* num_used,
const uint16_t* const clusters, uint16_t* const cluster_mappings, const uint32_t* const clusters, uint16_t* const cluster_mappings,
VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins, VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins,
int32_t combine_cost_factor, int low_effort) { int32_t combine_cost_factor, int low_effort) {
VP8LHistogram** const histograms = image_histo->histograms; VP8LHistogram** const histograms = image_histo->histograms;
@ -1070,7 +1070,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
// Note: we assume that out[]->bit_cost_ is already up-to-date. // Note: we assume that out[]->bit_cost_ is already up-to-date.
static void HistogramRemap(const VP8LHistogramSet* const in, static void HistogramRemap(const VP8LHistogramSet* const in,
VP8LHistogramSet* const out, VP8LHistogramSet* const out,
uint16_t* const symbols) { uint32_t* const symbols) {
int i; int i;
VP8LHistogram** const in_histo = in->histograms; VP8LHistogram** const in_histo = in->histograms;
VP8LHistogram** const out_histo = out->histograms; VP8LHistogram** const out_histo = out->histograms;
@ -1131,10 +1131,10 @@ static int32_t GetCombineCostFactor(int histo_size, int quality) {
// assign the smallest possible clusters values. // assign the smallest possible clusters values.
static void OptimizeHistogramSymbols(const VP8LHistogramSet* const set, static void OptimizeHistogramSymbols(const VP8LHistogramSet* const set,
uint16_t* const cluster_mappings, uint16_t* const cluster_mappings,
int num_clusters, uint32_t num_clusters,
uint16_t* const cluster_mappings_tmp, uint16_t* const cluster_mappings_tmp,
uint16_t* const symbols) { uint32_t* const symbols) {
int i, cluster_max; uint32_t i, cluster_max;
int do_continue = 1; int do_continue = 1;
// First, assign the lowest cluster to each pixel. // First, assign the lowest cluster to each pixel.
while (do_continue) { while (do_continue) {
@ -1158,7 +1158,7 @@ static void OptimizeHistogramSymbols(const VP8LHistogramSet* const set,
set->max_size * sizeof(*cluster_mappings_tmp)); set->max_size * sizeof(*cluster_mappings_tmp));
assert(cluster_mappings[0] == 0); assert(cluster_mappings[0] == 0);
// Re-map the ids. // Re-map the ids.
for (i = 0; i < set->max_size; ++i) { for (i = 0; i < (uint32_t)set->max_size; ++i) {
int cluster; int cluster;
if (symbols[i] == kInvalidHistogramSymbol) continue; if (symbols[i] == kInvalidHistogramSymbol) continue;
cluster = cluster_mappings[symbols[i]]; cluster = cluster_mappings[symbols[i]];
@ -1172,7 +1172,7 @@ static void OptimizeHistogramSymbols(const VP8LHistogramSet* const set,
// Make sure all cluster values are used. // Make sure all cluster values are used.
cluster_max = 0; cluster_max = 0;
for (i = 0; i < set->max_size; ++i) { for (i = 0; i < (uint32_t)set->max_size; ++i) {
if (symbols[i] == kInvalidHistogramSymbol) continue; if (symbols[i] == kInvalidHistogramSymbol) continue;
if (symbols[i] <= cluster_max) continue; if (symbols[i] <= cluster_max) continue;
++cluster_max; ++cluster_max;
@ -1195,7 +1195,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
int low_effort, int histogram_bits, int cache_bits, int low_effort, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo, VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo, VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols, uint32_t* const histogram_symbols,
const WebPPicture* const pic, int percent_range, const WebPPicture* const pic, int percent_range,
int* const percent) { int* const percent) {
const int histo_xsize = const int histo_xsize =

View File

@ -109,7 +109,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
int low_effort, int histogram_bits, int cache_bits, int low_effort, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo, VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo, VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols, uint32_t* const histogram_symbols,
const WebPPicture* const pic, int percent_range, const WebPPicture* const pic, int percent_range,
int* const percent); int* const percent);

View File

@ -664,11 +664,12 @@ static WEBP_INLINE void WriteHuffmanCodeWithExtraBits(
VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits); VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits);
} }
static int StoreImageToBitMask( static int StoreImageToBitMask(VP8LBitWriter* const bw, int width,
VP8LBitWriter* const bw, int width, int histo_bits, int histo_bits,
const VP8LBackwardRefs* const refs, const VP8LBackwardRefs* const refs,
const uint16_t* histogram_symbols, const uint32_t* histogram_symbols,
const HuffmanTreeCode* const huffman_codes, const WebPPicture* const pic) { const HuffmanTreeCode* const huffman_codes,
const WebPPicture* const pic) {
const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1; const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits); const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits);
// x and y trace the position in the image. // x and y trace the position in the image.
@ -676,7 +677,7 @@ static int StoreImageToBitMask(
int y = 0; int y = 0;
int tile_x = x & tile_mask; int tile_x = x & tile_mask;
int tile_y = y & tile_mask; int tile_y = y & tile_mask;
int histogram_ix = histogram_symbols[0]; int histogram_ix = (histogram_symbols[0] >> 8) & 0xffff;
const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix; const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix;
VP8LRefsCursor c = VP8LRefsCursorInit(refs); VP8LRefsCursor c = VP8LRefsCursorInit(refs);
while (VP8LRefsCursorOk(&c)) { while (VP8LRefsCursorOk(&c)) {
@ -684,8 +685,10 @@ static int StoreImageToBitMask(
if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) { if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) {
tile_x = x & tile_mask; tile_x = x & tile_mask;
tile_y = y & tile_mask; tile_y = y & tile_mask;
histogram_ix = histogram_symbols[(y >> histo_bits) * histo_xsize + histogram_ix = (histogram_symbols[(y >> histo_bits) * histo_xsize +
(x >> histo_bits)]; (x >> histo_bits)] >>
8) &
0xffff;
codes = huffman_codes + 5 * histogram_ix; codes = huffman_codes + 5 * histogram_ix;
} }
if (PixOrCopyIsLiteral(v)) { if (PixOrCopyIsLiteral(v)) {
@ -741,7 +744,7 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
VP8LBackwardRefs* refs; VP8LBackwardRefs* refs;
HuffmanTreeToken* tokens = NULL; HuffmanTreeToken* tokens = NULL;
HuffmanTreeCode huffman_codes[5] = {{0, NULL, NULL}}; HuffmanTreeCode huffman_codes[5] = {{0, NULL, NULL}};
const uint16_t histogram_symbols[1] = {0}; // only one tree, one symbol const uint32_t histogram_symbols[1] = {0}; // only one tree, one symbol
int cache_bits = 0; int cache_bits = 0;
VP8LHistogramSet* histogram_image = NULL; VP8LHistogramSet* histogram_image = NULL;
HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
@ -834,14 +837,14 @@ static int EncodeImageInternal(
int percent_start = *percent; int percent_start = *percent;
VP8LHistogramSet* histogram_image = NULL; VP8LHistogramSet* histogram_image = NULL;
VP8LHistogram* tmp_histo = NULL; VP8LHistogram* tmp_histo = NULL;
int histogram_image_size = 0; uint32_t i, histogram_image_size = 0;
size_t bit_array_size = 0; size_t bit_array_size = 0;
HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
HuffmanTreeToken* tokens = NULL; HuffmanTreeToken* tokens = NULL;
HuffmanTreeCode* huffman_codes = NULL; HuffmanTreeCode* huffman_codes = NULL;
uint16_t* const histogram_symbols = (uint16_t*)WebPSafeMalloc( uint32_t* const histogram_argb = (uint32_t*)WebPSafeMalloc(
histogram_image_xysize, sizeof(*histogram_symbols)); histogram_image_xysize, sizeof(*histogram_argb));
int sub_configs_idx; int sub_configs_idx;
int cache_bits_init, write_histogram_image; int cache_bits_init, write_histogram_image;
VP8LBitWriter bw_init = *bw, bw_best; VP8LBitWriter bw_init = *bw, bw_best;
@ -860,7 +863,7 @@ static int EncodeImageInternal(
} }
// Make sure we can allocate the different objects. // Make sure we can allocate the different objects.
if (huff_tree == NULL || histogram_symbols == NULL || if (huff_tree == NULL || histogram_argb == NULL ||
!VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize)) { !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize)) {
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error; goto Error;
@ -923,7 +926,7 @@ static int EncodeImageInternal(
if (!VP8LGetHistoImageSymbols( if (!VP8LGetHistoImageSymbols(
width, height, &refs_array[i_cache], quality, low_effort, width, height, &refs_array[i_cache], quality, low_effort,
histogram_bits, cache_bits_tmp, histogram_image, tmp_histo, histogram_bits, cache_bits_tmp, histogram_image, tmp_histo,
histogram_symbols, pic, i_percent_range, percent)) { histogram_argb, pic, i_percent_range, percent)) {
goto Error; goto Error;
} }
// Create Huffman bit lengths and codes for each histogram image. // Create Huffman bit lengths and codes for each histogram image.
@ -956,26 +959,17 @@ static int EncodeImageInternal(
} }
// Huffman image + meta huffman. // Huffman image + meta huffman.
histogram_image_size = 0;
for (i = 0; i < histogram_image_xysize; ++i) {
if (histogram_argb[i] >= histogram_image_size) {
histogram_image_size = histogram_argb[i] + 1;
}
histogram_argb[i] <<= 8;
}
write_histogram_image = (histogram_image_size > 1); write_histogram_image = (histogram_image_size > 1);
VP8LPutBits(bw, write_histogram_image, 1); VP8LPutBits(bw, write_histogram_image, 1);
if (write_histogram_image) { if (write_histogram_image) {
uint32_t* const histogram_argb = (uint32_t*)WebPSafeMalloc(
histogram_image_xysize, sizeof(*histogram_argb));
int max_index = 0;
uint32_t i;
if (histogram_argb == NULL) {
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
for (i = 0; i < histogram_image_xysize; ++i) {
const int symbol_index = histogram_symbols[i] & 0xffff;
histogram_argb[i] = (symbol_index << 8);
if (symbol_index >= max_index) {
max_index = symbol_index + 1;
}
}
histogram_image_size = max_index;
VP8LPutBits(bw, histogram_bits - 2, 3); VP8LPutBits(bw, histogram_bits - 2, 3);
i_percent_range = i_remaining_percent / 2; i_percent_range = i_remaining_percent / 2;
i_remaining_percent -= i_percent_range; i_remaining_percent -= i_percent_range;
@ -984,15 +978,12 @@ static int EncodeImageInternal(
VP8LSubSampleSize(width, histogram_bits), VP8LSubSampleSize(width, histogram_bits),
VP8LSubSampleSize(height, histogram_bits), quality, low_effort, VP8LSubSampleSize(height, histogram_bits), quality, low_effort,
pic, i_percent_range, percent)) { pic, i_percent_range, percent)) {
WebPSafeFree(histogram_argb);
goto Error; goto Error;
} }
WebPSafeFree(histogram_argb);
} }
// Store Huffman codes. // Store Huffman codes.
{ {
int i;
int max_tokens = 0; int max_tokens = 0;
// Find maximum number of symbols for the huffman tree-set. // Find maximum number of symbols for the huffman tree-set.
for (i = 0; i < 5 * histogram_image_size; ++i) { for (i = 0; i < 5 * histogram_image_size; ++i) {
@ -1015,7 +1006,7 @@ static int EncodeImageInternal(
// Store actual literals. // Store actual literals.
hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position); hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
if (!StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache], if (!StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache],
histogram_symbols, huffman_codes, pic)) { histogram_argb, huffman_codes, pic)) {
goto Error; goto Error;
} }
// Keep track of the smallest image so far. // Keep track of the smallest image so far.
@ -1052,7 +1043,7 @@ static int EncodeImageInternal(
WebPSafeFree(huffman_codes->codes); WebPSafeFree(huffman_codes->codes);
WebPSafeFree(huffman_codes); WebPSafeFree(huffman_codes);
} }
WebPSafeFree(histogram_symbols); WebPSafeFree(histogram_argb);
VP8LBitWriterWipeOut(&bw_best); VP8LBitWriterWipeOut(&bw_best);
return (pic->error_code == VP8_ENC_OK); return (pic->error_code == VP8_ENC_OK);
} }