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:
Pascal Massimino 2012-04-25 13:37:36 +00:00 committed by James Zern
parent fbb501b8ee
commit 31035f3b49

View File

@ -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, static int GetBackwardReferences(int width, int height,
const uint32_t* argb, const uint32_t* argb,
int quality, int use_color_cache, int quality, int use_color_cache,
int cache_bits, int use_2d_locality, int cache_bits, int use_2d_locality,
PixOrCopy** backward_refs, VP8LBackwardRefs* const best) {
int* backward_refs_size) {
int ok = 0; int ok = 0;
// Backward Reference using LZ77.
int lz77_is_useful; int lz77_is_useful;
int backward_refs_rle_size; VP8LBackwardRefs refs_rle, refs_lz77;
int backward_refs_lz77_size;
const int num_pix = width * height; const int num_pix = width * height;
VP8LHistogram* histo_rle; refs_rle.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_rle.refs));
PixOrCopy* backward_refs_lz77 = (PixOrCopy*) refs_lz77.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_lz77.refs));
malloc(num_pix * sizeof(*backward_refs_lz77));
PixOrCopy* backward_refs_rle = (PixOrCopy*) VP8LInitBackwardRefs(best);
malloc(num_pix * sizeof(*backward_refs_lz77)); if (refs_rle.refs == NULL || refs_lz77.refs == NULL) {
VP8LHistogram* histo_lz77 = (VP8LHistogram*)malloc(2 * sizeof(*histo_lz77)); Error1:
if (backward_refs_lz77 == NULL || backward_refs_rle == NULL || VP8LClearBackwardRefs(&refs_rle);
histo_lz77 == NULL) { VP8LClearBackwardRefs(&refs_lz77);
free(backward_refs_lz77);
free(backward_refs_rle);
goto End; goto End;
} }
*backward_refs = NULL;
histo_rle = histo_lz77 + 1;
if (!VP8LBackwardReferencesHashChain(width, height, use_color_cache, if (!VP8LBackwardReferencesHashChain(width, height, use_color_cache,
argb, cache_bits, quality, argb, cache_bits, quality,
backward_refs_lz77, refs_lz77.refs, &refs_lz77.size)) {
&backward_refs_lz77_size)) {
goto End; goto End;
} }
VP8LHistogramInit(histo_lz77, cache_bits);
VP8LHistogramCreate(histo_lz77, backward_refs_lz77, backward_refs_lz77_size);
// Backward Reference using RLE only. // Backward Reference using RLE only.
VP8LBackwardReferencesRle(width, height, argb, backward_refs_rle, VP8LBackwardReferencesRle(width, height, argb, refs_rle.refs, &refs_rle.size);
&backward_refs_rle_size);
VP8LHistogramInit(histo_rle, cache_bits); {
VP8LHistogramCreate(histo_rle, backward_refs_rle, backward_refs_rle_size); int bit_cost_lz77, bit_cost_rle;
VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
// Check if LZ77 is useful. if (histo == NULL) goto Error1;
lz77_is_useful = (VP8LHistogramEstimateBits(histo_rle) > // Evaluate lz77 coding
VP8LHistogramEstimateBits(histo_lz77)); 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. // Choose appropriate backward reference.
if (lz77_is_useful) { if (lz77_is_useful) {
// TraceBackwards is costly. Run it for higher qualities. // TraceBackwards is costly. Run it for higher qualities.
const int try_lz77_trace_backwards = (quality >= 75); 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) { if (try_lz77_trace_backwards) {
const int recursion_level = (num_pix < 320 * 200) ? 1 : 0; const int recursion_level = (num_pix < 320 * 200) ? 1 : 0;
int backward_refs_trace_size; VP8LBackwardRefs refs_trace;
PixOrCopy* backward_refs_trace; refs_trace.refs = (PixOrCopy*)malloc(num_pix * sizeof(*refs_trace.refs));
backward_refs_trace = if (refs_trace.refs == NULL) {
(PixOrCopy*)malloc(num_pix * sizeof(*backward_refs_trace));
if (backward_refs_trace == NULL) {
free(backward_refs_lz77);
goto End; goto End;
} }
if (VP8LBackwardReferencesTraceBackwards(width, height, recursion_level, if (VP8LBackwardReferencesTraceBackwards(width, height, recursion_level,
use_color_cache, argb, use_color_cache,
cache_bits, backward_refs_trace, argb, cache_bits,
&backward_refs_trace_size)) { refs_trace.refs,
free(backward_refs_lz77); &refs_trace.size)) {
*backward_refs = backward_refs_trace; VP8LClearBackwardRefs(&refs_lz77);
*backward_refs_size = backward_refs_trace_size; *best = refs_trace;
} else {
free(backward_refs_trace);
*backward_refs = backward_refs_lz77;
*backward_refs_size = backward_refs_lz77_size;
} }
} else {
*backward_refs = backward_refs_lz77;
*backward_refs_size = backward_refs_lz77_size;
} }
} else { } else {
free(backward_refs_lz77); VP8LClearBackwardRefs(&refs_lz77);
*backward_refs = backward_refs_rle; *best = refs_rle;
*backward_refs_size = backward_refs_rle_size;
} }
if (use_2d_locality) { if (use_2d_locality) { // Use backward reference with 2D locality.
// Use backward reference with 2D locality. VP8LBackwardReferences2DLocality(width, best->size, best->refs);
VP8LBackwardReferences2DLocality(width, *backward_refs_size,
*backward_refs);
} }
ok = 1; ok = 1;
End: End:
free(histo_lz77);
if (!ok) { if (!ok) {
free(*backward_refs); VP8LClearBackwardRefs(best);
*backward_refs = NULL;
} }
return ok; return ok;
} }
@ -739,13 +744,12 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
uint8_t** bit_lengths = NULL; uint8_t** bit_lengths = NULL;
uint16_t** bit_codes = NULL; uint16_t** bit_codes = NULL;
const int use_2d_locality = 1; const int use_2d_locality = 1;
int backward_refs_size;
const int use_color_cache = (cache_bits > 0); const int use_color_cache = (cache_bits > 0);
const int color_cache_size = use_color_cache ? (1 << cache_bits) : 0; const int color_cache_size = use_color_cache ? (1 << cache_bits) : 0;
const int histogram_image_xysize = VP8LSubSampleSize(width, histogram_bits) * const int histogram_image_xysize = VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits); VP8LSubSampleSize(height, histogram_bits);
VP8LHistogram** histogram_image; VP8LHistogram** histogram_image;
PixOrCopy* backward_refs; VP8LBackwardRefs refs;
const size_t histo_size = histogram_image_xysize * sizeof(uint32_t); const size_t histo_size = histogram_image_xysize * sizeof(uint32_t);
uint32_t* const histogram_symbols = (uint32_t*)calloc(1, histo_size); 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. // Calculate backward references from ARGB image.
if (!GetBackwardReferences(width, height, argb, quality, if (!GetBackwardReferences(width, height, argb, quality,
use_color_cache, cache_bits, use_2d_locality, use_color_cache, cache_bits, use_2d_locality,
&backward_refs, &backward_refs_size)) { &refs)) {
goto Error; goto Error;
} }
// Build histogram image & symbols from backward references. // 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, quality, histogram_bits, cache_bits,
&histogram_image, &histogram_image_size, &histogram_image, &histogram_image_size,
histogram_symbols)) { histogram_symbols)) {
@ -834,16 +838,15 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
bit_codes[i]); bit_codes[i]);
} }
// Store actual literals. // Store actual literals.
StoreImageToBitMask(bw, width, histogram_bits, backward_refs, StoreImageToBitMask(bw, width, histogram_bits, refs.refs, refs.size,
backward_refs_size, histogram_symbols, histogram_symbols, bit_lengths, bit_codes);
bit_lengths, bit_codes);
ok = 1; ok = 1;
Error: Error:
if (!ok) { if (!ok) {
DeleteHistograms(histogram_image, histogram_image_size); DeleteHistograms(histogram_image, histogram_image_size);
} }
free(backward_refs); VP8LClearBackwardRefs(&refs);
for (i = 0; i < 5 * histogram_image_size; ++i) { for (i = 0; i < 5 * histogram_image_size; ++i) {
free(bit_lengths[i]); free(bit_lengths[i]);
free(bit_codes[i]); free(bit_codes[i]);