mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01:00
reduce memory usage by allocating only one histo
instead of lz77+rle * introduce VP8LBackwardRefs structure and simplify the code by not passing around {PixOrCopy/int} pairs. More functions should be turned into using this struct (TODO(later)). Change-Id: I69c5c9fa61dddd61a2abc2824d70b8606a1c55b6
This commit is contained in:
parent
fbb501b8ee
commit
31035f3b49
139
src/enc/vp8l.c
139
src/enc/vp8l.c
@ -165,102 +165,107 @@ static void BundleColorMap(const uint32_t* const argb,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(urvang): should be moved to backward_reference.h and used more
|
||||
// as function parameters.
|
||||
typedef struct {
|
||||
PixOrCopy* refs;
|
||||
int size;
|
||||
} VP8LBackwardRefs;
|
||||
|
||||
static void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs) {
|
||||
if (refs != NULL) {
|
||||
refs->refs = NULL;
|
||||
refs->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) {
|
||||
if (refs != NULL) {
|
||||
free(refs->refs);
|
||||
VP8LInitBackwardRefs(refs);
|
||||
}
|
||||
}
|
||||
|
||||
static int GetBackwardReferences(int width, int height,
|
||||
const uint32_t* argb,
|
||||
int quality, int use_color_cache,
|
||||
int cache_bits, int use_2d_locality,
|
||||
PixOrCopy** backward_refs,
|
||||
int* backward_refs_size) {
|
||||
VP8LBackwardRefs* const best) {
|
||||
int ok = 0;
|
||||
// Backward Reference using LZ77.
|
||||
int lz77_is_useful;
|
||||
int backward_refs_rle_size;
|
||||
int backward_refs_lz77_size;
|
||||
VP8LBackwardRefs refs_rle, refs_lz77;
|
||||
const int num_pix = width * height;
|
||||
VP8LHistogram* histo_rle;
|
||||
PixOrCopy* backward_refs_lz77 = (PixOrCopy*)
|
||||
malloc(num_pix * sizeof(*backward_refs_lz77));
|
||||
PixOrCopy* backward_refs_rle = (PixOrCopy*)
|
||||
malloc(num_pix * sizeof(*backward_refs_lz77));
|
||||
VP8LHistogram* histo_lz77 = (VP8LHistogram*)malloc(2 * sizeof(*histo_lz77));
|
||||
if (backward_refs_lz77 == NULL || backward_refs_rle == NULL ||
|
||||
histo_lz77 == NULL) {
|
||||
free(backward_refs_lz77);
|
||||
free(backward_refs_rle);
|
||||
refs_rle.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_rle.refs));
|
||||
refs_lz77.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_lz77.refs));
|
||||
|
||||
VP8LInitBackwardRefs(best);
|
||||
if (refs_rle.refs == NULL || refs_lz77.refs == NULL) {
|
||||
Error1:
|
||||
VP8LClearBackwardRefs(&refs_rle);
|
||||
VP8LClearBackwardRefs(&refs_lz77);
|
||||
goto End;
|
||||
}
|
||||
*backward_refs = NULL;
|
||||
histo_rle = histo_lz77 + 1;
|
||||
|
||||
if (!VP8LBackwardReferencesHashChain(width, height, use_color_cache,
|
||||
argb, cache_bits, quality,
|
||||
backward_refs_lz77,
|
||||
&backward_refs_lz77_size)) {
|
||||
refs_lz77.refs, &refs_lz77.size)) {
|
||||
goto End;
|
||||
}
|
||||
VP8LHistogramInit(histo_lz77, cache_bits);
|
||||
VP8LHistogramCreate(histo_lz77, backward_refs_lz77, backward_refs_lz77_size);
|
||||
|
||||
// Backward Reference using RLE only.
|
||||
VP8LBackwardReferencesRle(width, height, argb, backward_refs_rle,
|
||||
&backward_refs_rle_size);
|
||||
VP8LBackwardReferencesRle(width, height, argb, refs_rle.refs, &refs_rle.size);
|
||||
|
||||
VP8LHistogramInit(histo_rle, cache_bits);
|
||||
VP8LHistogramCreate(histo_rle, backward_refs_rle, backward_refs_rle_size);
|
||||
|
||||
// Check if LZ77 is useful.
|
||||
lz77_is_useful = (VP8LHistogramEstimateBits(histo_rle) >
|
||||
VP8LHistogramEstimateBits(histo_lz77));
|
||||
{
|
||||
int bit_cost_lz77, bit_cost_rle;
|
||||
VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
|
||||
if (histo == NULL) goto Error1;
|
||||
// Evaluate lz77 coding
|
||||
VP8LHistogramInit(histo, cache_bits);
|
||||
VP8LHistogramCreate(histo, refs_lz77.refs, refs_lz77.size);
|
||||
bit_cost_lz77 = (int)VP8LHistogramEstimateBits(histo);
|
||||
// Evaluate RLE coding
|
||||
VP8LHistogramInit(histo, cache_bits);
|
||||
VP8LHistogramCreate(histo, refs_rle.refs, refs_rle.size);
|
||||
bit_cost_rle = (int)VP8LHistogramEstimateBits(histo);
|
||||
// Decide if LZ77 is useful.
|
||||
lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
|
||||
free(histo);
|
||||
}
|
||||
|
||||
// Choose appropriate backward reference.
|
||||
if (lz77_is_useful) {
|
||||
// TraceBackwards is costly. Run it for higher qualities.
|
||||
const int try_lz77_trace_backwards = (quality >= 75);
|
||||
free(backward_refs_rle);
|
||||
*best = refs_lz77; // default guess: lz77 is better
|
||||
VP8LClearBackwardRefs(&refs_rle);
|
||||
if (try_lz77_trace_backwards) {
|
||||
const int recursion_level = (num_pix < 320 * 200) ? 1 : 0;
|
||||
int backward_refs_trace_size;
|
||||
PixOrCopy* backward_refs_trace;
|
||||
backward_refs_trace =
|
||||
(PixOrCopy*)malloc(num_pix * sizeof(*backward_refs_trace));
|
||||
if (backward_refs_trace == NULL) {
|
||||
free(backward_refs_lz77);
|
||||
VP8LBackwardRefs refs_trace;
|
||||
refs_trace.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_trace.refs));
|
||||
if (refs_trace.refs == NULL) {
|
||||
goto End;
|
||||
}
|
||||
if (VP8LBackwardReferencesTraceBackwards(width, height, recursion_level,
|
||||
use_color_cache, argb,
|
||||
cache_bits, backward_refs_trace,
|
||||
&backward_refs_trace_size)) {
|
||||
free(backward_refs_lz77);
|
||||
*backward_refs = backward_refs_trace;
|
||||
*backward_refs_size = backward_refs_trace_size;
|
||||
} else {
|
||||
free(backward_refs_trace);
|
||||
*backward_refs = backward_refs_lz77;
|
||||
*backward_refs_size = backward_refs_lz77_size;
|
||||
use_color_cache,
|
||||
argb, cache_bits,
|
||||
refs_trace.refs,
|
||||
&refs_trace.size)) {
|
||||
VP8LClearBackwardRefs(&refs_lz77);
|
||||
*best = refs_trace;
|
||||
}
|
||||
} else {
|
||||
*backward_refs = backward_refs_lz77;
|
||||
*backward_refs_size = backward_refs_lz77_size;
|
||||
}
|
||||
} else {
|
||||
free(backward_refs_lz77);
|
||||
*backward_refs = backward_refs_rle;
|
||||
*backward_refs_size = backward_refs_rle_size;
|
||||
VP8LClearBackwardRefs(&refs_lz77);
|
||||
*best = refs_rle;
|
||||
}
|
||||
|
||||
if (use_2d_locality) {
|
||||
// Use backward reference with 2D locality.
|
||||
VP8LBackwardReferences2DLocality(width, *backward_refs_size,
|
||||
*backward_refs);
|
||||
if (use_2d_locality) { // Use backward reference with 2D locality.
|
||||
VP8LBackwardReferences2DLocality(width, best->size, best->refs);
|
||||
}
|
||||
ok = 1;
|
||||
|
||||
End:
|
||||
free(histo_lz77);
|
||||
if (!ok) {
|
||||
free(*backward_refs);
|
||||
*backward_refs = NULL;
|
||||
VP8LClearBackwardRefs(best);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@ -739,13 +744,12 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
uint8_t** bit_lengths = NULL;
|
||||
uint16_t** bit_codes = NULL;
|
||||
const int use_2d_locality = 1;
|
||||
int backward_refs_size;
|
||||
const int use_color_cache = (cache_bits > 0);
|
||||
const int color_cache_size = use_color_cache ? (1 << cache_bits) : 0;
|
||||
const int histogram_image_xysize = VP8LSubSampleSize(width, histogram_bits) *
|
||||
VP8LSubSampleSize(height, histogram_bits);
|
||||
VP8LHistogram** histogram_image;
|
||||
PixOrCopy* backward_refs;
|
||||
VP8LBackwardRefs refs;
|
||||
const size_t histo_size = histogram_image_xysize * sizeof(uint32_t);
|
||||
uint32_t* const histogram_symbols = (uint32_t*)calloc(1, histo_size);
|
||||
|
||||
@ -754,11 +758,11 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
// Calculate backward references from ARGB image.
|
||||
if (!GetBackwardReferences(width, height, argb, quality,
|
||||
use_color_cache, cache_bits, use_2d_locality,
|
||||
&backward_refs, &backward_refs_size)) {
|
||||
&refs)) {
|
||||
goto Error;
|
||||
}
|
||||
// Build histogram image & symbols from backward references.
|
||||
if (!GetHistImageSymbols(width, height, backward_refs, backward_refs_size,
|
||||
if (!GetHistImageSymbols(width, height, refs.refs, refs.size,
|
||||
quality, histogram_bits, cache_bits,
|
||||
&histogram_image, &histogram_image_size,
|
||||
histogram_symbols)) {
|
||||
@ -834,16 +838,15 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
bit_codes[i]);
|
||||
}
|
||||
// Store actual literals.
|
||||
StoreImageToBitMask(bw, width, histogram_bits, backward_refs,
|
||||
backward_refs_size, histogram_symbols,
|
||||
bit_lengths, bit_codes);
|
||||
StoreImageToBitMask(bw, width, histogram_bits, refs.refs, refs.size,
|
||||
histogram_symbols, bit_lengths, bit_codes);
|
||||
ok = 1;
|
||||
|
||||
Error:
|
||||
if (!ok) {
|
||||
DeleteHistograms(histogram_image, histogram_image_size);
|
||||
}
|
||||
free(backward_refs);
|
||||
VP8LClearBackwardRefs(&refs);
|
||||
for (i = 0; i < 5 * histogram_image_size; ++i) {
|
||||
free(bit_lengths[i]);
|
||||
free(bit_codes[i]);
|
||||
|
Loading…
Reference in New Issue
Block a user